summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets')
-rw-r--r--tests/auto/widgets/CMakeLists.txt32
-rw-r--r--tests/auto/widgets/accessibility/BLACKLIST5
-rw-r--r--tests/auto/widgets/accessibility/CMakeLists.txt13
-rw-r--r--tests/auto/widgets/accessibility/accessibility.pro1
-rw-r--r--tests/auto/widgets/accessibility/tst_accessibility.cpp164
-rw-r--r--tests/auto/widgets/certificateerror/certificateerror.pro3
-rw-r--r--tests/auto/widgets/certificateerror/tst_certificateerror.cpp124
-rw-r--r--tests/auto/widgets/defaultsurfaceformat/CMakeLists.txt23
-rw-r--r--tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro1
-rw-r--r--tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp31
-rw-r--r--tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc5
-rw-r--r--tests/auto/widgets/devtools/devtools.pro1
-rw-r--r--tests/auto/widgets/devtools/tst_devtools.cpp87
-rw-r--r--tests/auto/widgets/favicon/CMakeLists.txt32
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-misc.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-misc.html)4
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-multi.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-multi.html)2
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-shortcut.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html)0
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-single.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-single.html)0
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-touch.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-touch.html)0
-rw-r--r--tests/auto/widgets/favicon/resources/favicon-unavailable.html (renamed from tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html)0
-rw-r--r--tests/auto/widgets/favicon/resources/icons/qt144.png (renamed from tests/auto/widgets/faviconmanager/resources/icons/qt144.png)bin8315 -> 8315 bytes
-rw-r--r--tests/auto/widgets/favicon/resources/icons/qt32.ico (renamed from tests/auto/widgets/faviconmanager/resources/icons/qt32.ico)bin4286 -> 4286 bytes
-rw-r--r--tests/auto/widgets/favicon/resources/icons/qtmulti.ico (renamed from tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico)bin22382 -> 22382 bytes
-rw-r--r--tests/auto/widgets/favicon/resources/test1.html (renamed from tests/auto/widgets/faviconmanager/resources/test1.html)0
-rw-r--r--tests/auto/widgets/favicon/tst_favicon.cpp869
-rw-r--r--tests/auto/widgets/faviconmanager/faviconmanager.pro1
-rw-r--r--tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp551
-rw-r--r--tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc14
-rw-r--r--tests/auto/widgets/loadsignals/BLACKLIST14
-rw-r--r--tests/auto/widgets/loadsignals/CMakeLists.txt63
-rw-r--r--tests/auto/widgets/loadsignals/loadsignals.pro1
-rw-r--r--tests/auto/widgets/loadsignals/resources/downloadable.tar.gzbin131 -> 0 bytes
-rw-r--r--tests/auto/widgets/loadsignals/resources/page1.html8
-rw-r--r--tests/auto/widgets/loadsignals/resources/page2.html14
-rw-r--r--tests/auto/widgets/loadsignals/resources/page3.html20
-rw-r--r--tests/auto/widgets/loadsignals/resources/page4.html8
-rw-r--r--tests/auto/widgets/loadsignals/tst_loadsignals.cpp609
-rw-r--r--tests/auto/widgets/loadsignals/tst_loadsignals.qrc9
-rw-r--r--tests/auto/widgets/offscreen/CMakeLists.txt25
-rw-r--r--tests/auto/widgets/offscreen/offscreen.pro6
-rw-r--r--tests/auto/widgets/offscreen/tst_offscreen.cpp32
-rw-r--r--tests/auto/widgets/offscreen/tst_offscreen.qrc6
-rw-r--r--tests/auto/widgets/origins/origins.pro7
-rw-r--r--tests/auto/widgets/origins/resources/createObjectURL.html11
-rw-r--r--tests/auto/widgets/origins/resources/dedicatedWorker.html19
-rw-r--r--tests/auto/widgets/origins/resources/dedicatedWorker.js1
-rw-r--r--tests/auto/widgets/origins/resources/mixedSchemes.html31
-rw-r--r--tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html32
-rw-r--r--tests/auto/widgets/origins/resources/mixedSchemes_frame.html11
-rw-r--r--tests/auto/widgets/origins/resources/mixedXHR.html19
-rw-r--r--tests/auto/widgets/origins/resources/mixedXHR.txt1
-rw-r--r--tests/auto/widgets/origins/resources/redirect.css8
-rw-r--r--tests/auto/widgets/origins/resources/redirect.html10
-rw-r--r--tests/auto/widgets/origins/resources/serviceWorker.html18
-rw-r--r--tests/auto/widgets/origins/resources/serviceWorker.js1
-rw-r--r--tests/auto/widgets/origins/resources/sharedWorker.html19
-rw-r--r--tests/auto/widgets/origins/resources/sharedWorker.js6
-rw-r--r--tests/auto/widgets/origins/resources/subdir/frame2.html10
-rw-r--r--tests/auto/widgets/origins/resources/subdir/index.html26
-rw-r--r--tests/auto/widgets/origins/resources/subdir_frame1.html10
-rw-r--r--tests/auto/widgets/origins/resources/viewSource.html9
-rw-r--r--tests/auto/widgets/origins/resources/websocket.html23
-rw-r--r--tests/auto/widgets/origins/tst_origins.cpp874
-rw-r--r--tests/auto/widgets/origins/tst_origins.qrc22
-rw-r--r--tests/auto/widgets/printing/CMakeLists.txt34
-rw-r--r--tests/auto/widgets/printing/printing.pro10
-rw-r--r--tests/auto/widgets/printing/tst_printing.cpp156
-rw-r--r--tests/auto/widgets/printing/tst_printing.qrc5
-rw-r--r--tests/auto/widgets/proxy/CMakeLists.txt12
-rw-r--r--tests/auto/widgets/proxy/proxy.pro9
-rw-r--r--tests/auto/widgets/proxy/proxy_server.cpp102
-rw-r--r--tests/auto/widgets/proxy/proxy_server.h64
-rw-r--r--tests/auto/widgets/proxy/tst_proxy.cpp49
-rw-r--r--tests/auto/widgets/proxypac/CMakeLists.txt64
-rw-r--r--tests/auto/widgets/proxypac/proxy.pac2
-rw-r--r--tests/auto/widgets/proxypac/proxypac.pri5
-rw-r--r--tests/auto/widgets/proxypac/proxypac.pro4
-rw-r--r--tests/auto/widgets/proxypac/proxypac.qrc7
-rw-r--r--tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro9
-rw-r--r--tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro7
-rw-r--r--tests/auto/widgets/proxypac/proxyserver.cpp29
-rw-r--r--tests/auto/widgets/proxypac/proxyserver.h29
-rw-r--r--tests/auto/widgets/proxypac/tst_proxypac.cpp56
-rw-r--r--tests/auto/widgets/qtbug_110287/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/qtbug_110287/tst_qtbug_110287.cpp41
-rw-r--r--tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro3
-rw-r--r--tests/auto/widgets/qwebenginedownloadrequest/CMakeLists.txt14
-rw-r--r--tests/auto/widgets/qwebenginedownloadrequest/tst_qwebenginedownloadrequest.cpp (renamed from tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp)564
-rw-r--r--tests/auto/widgets/qwebenginehistory/CMakeLists.txt29
-rw-r--r--tests/auto/widgets/qwebenginehistory/qwebenginehistory.pro1
-rw-r--r--tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp47
-rw-r--r--tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.qrc10
-rw-r--r--tests/auto/widgets/qwebenginepage/BLACKLIST11
-rw-r--r--tests/auto/widgets/qwebenginepage/CMakeLists.txt68
-rw-r--r--tests/auto/widgets/qwebenginepage/qwebenginepage.pro3
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/fontaccess.html14
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/image2.png (renamed from tests/auto/widgets/resources/image2.png)bin14743 -> 14743 bytes
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/redirect.html8
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/reload.html2
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp2135
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc31
-rw-r--r--tests/auto/widgets/qwebengineprofile/CMakeLists.txt14
-rw-r--r--tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro4
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp326
-rw-r--r--tests/auto/widgets/qwebenginescript/CMakeLists.txt29
-rw-r--r--tests/auto/widgets/qwebenginescript/qwebenginescript.pro1
-rw-r--r--tests/auto/widgets/qwebenginescript/resources/test_window_open.html2
-rw-r--r--tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp171
-rw-r--r--tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc11
-rw-r--r--tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro2
-rw-r--r--tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp198
-rw-r--r--tests/auto/widgets/qwebengineview/BLACKLIST14
-rw-r--r--tests/auto/widgets/qwebengineview/CMakeLists.txt33
-rw-r--r--tests/auto/widgets/qwebengineview/qwebengineview.pro2
-rw-r--r--tests/auto/widgets/qwebengineview/resources/dummy.html6
-rw-r--r--tests/auto/widgets/qwebengineview/resources/test.swf (renamed from tests/auto/widgets/resources/test.swf)bin10085 -> 10085 bytes
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp1302
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc10
-rw-r--r--tests/auto/widgets/schemes/CMakeLists.txt13
-rw-r--r--tests/auto/widgets/schemes/schemes.pro3
-rw-r--r--tests/auto/widgets/schemes/tst_schemes.cpp215
-rw-r--r--tests/auto/widgets/shutdown/CMakeLists.txt9
-rw-r--r--tests/auto/widgets/shutdown/shutdown.pro1
-rw-r--r--tests/auto/widgets/shutdown/tst_shutdown.cpp40
-rw-r--r--tests/auto/widgets/spellchecking/CMakeLists.txt33
-rw-r--r--tests/auto/widgets/spellchecking/spellchecking.pro24
-rw-r--r--tests/auto/widgets/spellchecking/tst_spellchecking.cpp67
-rw-r--r--tests/auto/widgets/spellchecking/tst_spellchecking.qrc5
-rw-r--r--tests/auto/widgets/tests.pri22
-rw-r--r--tests/auto/widgets/touchinput/CMakeLists.txt13
-rw-r--r--tests/auto/widgets/touchinput/tst_touchinput.cpp372
-rw-r--r--tests/auto/widgets/util.h194
-rw-r--r--tests/auto/widgets/widgets.pro51
133 files changed, 5841 insertions, 4937 deletions
diff --git a/tests/auto/widgets/CMakeLists.txt b/tests/auto/widgets/CMakeLists.txt
new file mode 100644
index 000000000..9246be68a
--- /dev/null
+++ b/tests/auto/widgets/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(defaultsurfaceformat)
+add_subdirectory(qwebenginepage)
+add_subdirectory(qwebengineprofile)
+add_subdirectory(qwebengineview)
+add_subdirectory(favicon)
+add_subdirectory(loadsignals)
+add_subdirectory(proxy)
+add_subdirectory(proxypac)
+add_subdirectory(schemes)
+add_subdirectory(shutdown)
+add_subdirectory(qwebenginedownloadrequest)
+add_subdirectory(qwebenginehistory)
+add_subdirectory(qwebenginescript)
+if(LINUX)
+ add_subdirectory(offscreen)
+ add_subdirectory(qtbug_110287)
+endif()
+if(NOT MACOS)
+ add_subdirectory(touchinput)
+endif()
+if(QT_FEATURE_accessibility)
+ add_subdirectory(accessibility)
+endif()
+if(QT_FEATURE_webengine_printing_and_pdf)
+ add_subdirectory(printing)
+endif()
+if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING AND NOT QT_FEATURE_webengine_native_spellchecker)
+ add_subdirectory(spellchecking)
+endif()
diff --git a/tests/auto/widgets/accessibility/BLACKLIST b/tests/auto/widgets/accessibility/BLACKLIST
new file mode 100644
index 000000000..6fdb0dd58
--- /dev/null
+++ b/tests/auto/widgets/accessibility/BLACKLIST
@@ -0,0 +1,5 @@
+[roles:ax::mojom::Role::kSvgRoot]
+b2qt
+
+[focusChild]
+*
diff --git a/tests/auto/widgets/accessibility/CMakeLists.txt b/tests/auto/widgets/accessibility/CMakeLists.txt
new file mode 100644
index 000000000..f6a08c9d3
--- /dev/null
+++ b/tests/auto/widgets/accessibility/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_webengine_accessibility
+ SOURCES
+ tst_accessibility.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Qt::WebEngineCorePrivate
+ Test::Util
+)
diff --git a/tests/auto/widgets/accessibility/accessibility.pro b/tests/auto/widgets/accessibility/accessibility.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/accessibility/accessibility.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/accessibility/tst_accessibility.cpp b/tests/auto/widgets/accessibility/tst_accessibility.cpp
index 748837c7f..1579b61e2 100644
--- a/tests/auto/widgets/accessibility/tst_accessibility.cpp
+++ b/tests/auto/widgets/accessibility/tst_accessibility.cpp
@@ -17,8 +17,9 @@
Boston, MA 02110-1301, USA.
*/
+#include <QtWebEngineCore/private/qtwebenginecore-config_p.h>
#include <qtest.h>
-#include "../util.h"
+#include <widgetutil.h>
#include <QHBoxLayout>
#include <QMainWindow>
@@ -48,6 +49,9 @@ private Q_SLOTS:
void value();
void roles_data();
void roles();
+ void objectName();
+ void crossTreeParent();
+ void tableCellInterface();
};
// This will be called before the first test function is executed.
@@ -77,11 +81,10 @@ void tst_Accessibility::noPage()
QWebEngineView webView;
webView.show();
- QTest::qWait(1000);
- QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
- QVERIFY(view);
+ QAccessibleInterface *view = nullptr;
+ QTRY_VERIFY((view = QAccessible::queryAccessibleInterface(&webView)));
QCOMPARE(view->role(), QAccessible::Client);
- QCOMPARE(view->childCount(), 1);
+ QTRY_COMPARE(view->childCount(), 1);
QAccessibleInterface *document = view->child(0);
QCOMPARE(document->role(), QAccessible::WebDocument);
QCOMPARE(document->parent(), view);
@@ -104,7 +107,7 @@ void tst_Accessibility::hierarchy()
QCOMPARE(view->role(), QAccessible::Client);
QCOMPARE(view->childCount(), 1);
// Wait for accessibility to be fully initialized
- QTRY_VERIFY(view->child(0)->childCount() == 1);
+ QTRY_COMPARE(view->child(0)->childCount(), 1);
QAccessibleInterface *document = view->child(0);
QCOMPARE(document->role(), QAccessible::WebDocument);
QCOMPARE(document->parent(), view);
@@ -151,17 +154,17 @@ void tst_Accessibility::hierarchy()
void tst_Accessibility::focusChild_data()
{
QTest::addColumn<QString>("interfaceName");
- QTest::addColumn<QVector<QAccessible::Role>>("ancestorRoles");
+ QTest::addColumn<QList<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 */});
+ QTest::newRow("QWebEngineView") << QString("QWebEngineView") << QList<QAccessible::Role>({QAccessible::Client});
+ QTest::newRow("RenderWidgetHostViewQtDelegate") << QString("RenderWidgetHostViewQtDelegate") << QList<QAccessible::Role>({QAccessible::Client});
+ QTest::newRow("QMainWindow") << QString("QMainWindow") << QList<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);
+ QFETCH(QList<QAccessible::Role>, ancestorRoles);
for (int i = 0; i < ancestorRoles.size(); ++i) {
if (iface->childCount() == 0 || iface->role() != ancestorRoles[i])
return nullptr;
@@ -239,7 +242,7 @@ void tst_Accessibility::text()
QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
// Wait for accessibility to be fully initialized
- QTRY_VERIFY(view->child(0)->childCount() == 5);
+ QTRY_COMPARE(view->child(0)->childCount(), 5);
QAccessibleInterface *document = view->child(0);
QVERIFY(document);
@@ -339,7 +342,7 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kAbbr") << QString("<abbr>a</abbr>") << 1 << QAccessible::StaticText;
QTest::newRow("ax::mojom::Role::kAlert") << QString("<div role='alert'>alert</div>") << 0 << QAccessible::AlertMessage;
QTest::newRow("ax::mojom::Role::kAlertDialog") << QString("<div role='alertdialog'>alert</div>") << 0 << QAccessible::AlertMessage;
- QTest::newRow("ax::mojom::Role::kAnchor") << QString("<a id='a'>Chapter a</a>") << 1 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kAnchor") << QString("<a id='a'>Chapter a</a>") << 1 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kApplication") << QString("<div role='application'>landmark</div>") << 0 << QAccessible::Document;
QTest::newRow("ax::mojom::Role::kArticle") << QString("<article>a</article>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kAudio") << QString("<audio controls><source src='test.mp3' type='audio/mpeg'></audio>") << 1 << QAccessible::Sound;
@@ -361,7 +364,6 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kTextFieldWithComboBox") << QString("<input role='combobox'>") << 1 << QAccessible::ComboBox;
QTest::newRow("ax::mojom::Role::kComplementary") << QString("<aside>a</aside>") << 0 << QAccessible::ComplementaryContent;
QTest::newRow("ax::mojom::Role::kComment") << QString("<div role='comment'></div>") << 0 << QAccessible::Section;
- QTest::newRow("ax::mojom::Role::kCommenSection") << QString("<div role='commentsection'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kContentDeletion") << QString("<div role='deletion'></div>") << 0 << QAccessible::Grouping;
QTest::newRow("ax::mojom::Role::kContentInsertion") << QString("<div role='insertion'></div>") << 0 << QAccessible::Grouping;
QTest::newRow("ax::mojom::Role::kContentInfo") << QString("<div role='contentinfo'></div>") << 0 << QAccessible::Section;
@@ -402,8 +404,10 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kDocEpilogue") << QString("<div role='doc-epilogue'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kDocErrata") << QString("<div role='doc-errata'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kDocExample") << QString("<div role='doc-example'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocFooter") << QString("<section role='doc-pagefooter'>a</section>") << 0 << QAccessible::Footer;
QTest::newRow("ax::mojom::Role::kDocForeword") << QString("<div role='doc-foreword'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kDocGlossary") << QString("<div role='doc-glossary'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocHeader") << QString("<section role='doc-pageheader'>a</section>") << 0 << QAccessible::Heading;
QTest::newRow("ax::mojom::Role::kDocIndex") << QString("<div role='doc-index'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kDocIntroduction") << QString("<div role='doc-introduction'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kDocNotice") << QString("<div role='doc-notice'></div>") << 0 << QAccessible::Section;
@@ -422,9 +426,9 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kFeed") << QString("<div role='feed'>a</div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kFigcaption") << QString("<figcaption>a</figcaption>") << 0 << QAccessible::Heading;
QTest::newRow("ax::mojom::Role::kFigure") << QString("<figure>a</figure>") << 0 << QAccessible::Section;
- QTest::newRow("ax::mojom::Role::kFooter") << QString("<footer>a</footer>") << 0 << QAccessible::Footer;
+ QTest::newRow("ax::mojom::Role::kFooter") << QString("<footer>a</footer>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kFooterAsNonLandmark") << QString("<article><footer>a</footer><article>") << 1 << QAccessible::Section;
- QTest::newRow("ax::mojom::Role::kForm") << QString("<form></form>") << 0 << QAccessible::Form;
+ QTest::newRow("ax::mojom::Role::kForm") << QString("<form aria-label=Name></form>") << 0 << QAccessible::Form;
QTest::newRow("ax::mojom::Role::kGraphicsDocument") << QString("<div role='graphics-document'></div>") << 0 << QAccessible::Document;
QTest::newRow("ax::mojom::Role::kGraphicsObject") << QString("<div role='graphics-object'></div>") << 0 << QAccessible::Pane;
QTest::newRow("ax::mojom::Role::kGraphicsSymbol") << QString("<div role='graphics-symbol'></div>") << 0 << QAccessible::Graphic;
@@ -462,10 +466,10 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kMath") << QString("<math>a</math>") << 1 << QAccessible::Equation;
QTest::newRow("ax::mojom::Role::kMenu") << QString("<div role='menu'>a</div>") << 0 << QAccessible::PopupMenu;
QTest::newRow("ax::mojom::Role::kMenuBar") << QString("<div role='menubar'>a</div>") << 0 << QAccessible::MenuBar;
- QTest::newRow("ax::mojom::Role::kMenuItem") << QString("<menu role='menu'><input type='button' /></menu>") << 1 << QAccessible::MenuItem;
+ QTest::newRow("ax::mojom::Role::kMenuItem") << QString("<menu role='group'><div role='menuitem'>a</div></menu>") << 1 << QAccessible::MenuItem;
QTest::newRow("ax::mojom::Role::kMenuItemCheckBox") << QString("<menu role='menu'><input type='checkbox'></input></menu>") << 1 << QAccessible::CheckBox;
QTest::newRow("ax::mojom::Role::kMenuItemRadio") << QString("<menu role='menu'><input type='radio'></input></menu>") << 1 << QAccessible::RadioButton;
- QTest::newRow("ax::mojom::Role::kMenuButton") << QString("<menu role='group'><div role='menuitem'>a</div></menu>") << 1 << QAccessible::MenuItem;
+ QTest::newRow("ax::mojom::Role::kMenuButton") << QString("<menu role='menu'><input type='button' /></menu>") << 1 << QAccessible::Button;
QTest::newRow("ax::mojom::Role::kMenuListOption") << QString("<select role='menu'><option>a</option></select>") << 3 << QAccessible::MenuItem;
QTest::newRow("ax::mojom::Role::kMenuListPopup") << QString("<select role='menu'><option>a</option></select>") << 2 << QAccessible::PopupMenu;
QTest::newRow("ax::mojom::Role::kMeter") << QString("<meter>a</meter>") << 1 << QAccessible::Chart;
@@ -473,19 +477,18 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kNote") << QString("<div role='note'>a</div>") << 0 << QAccessible::Note;
//QTest::newRow("ax::mojom::Role::kPane"); // No mapping to ARIA role
QTest::newRow("ax::mojom::Role::kParagraph") << QString("<p>a</p>") << 0 << QAccessible::Paragraph;
- QTest::newRow("ax::mojom::Role::kPopUpButton") << QString("<select><option>a</option></select>") << 1 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kPopUpButton") << QString("<select><option>a</option></select>") << 1 << QAccessible::PopupMenu;
QTest::newRow("ax::mojom::Role::kPre") << QString("<pre>a</pre>") << 0 << QAccessible::Section;
//QTest::newRow("ax::mojom::Role::kPresentational") << QString("<div role='presentation'>a</div>") << 0 << QAccessible::NoRole; // FIXME: Aria role 'presentation' should work
QTest::newRow("ax::mojom::Role::kProgressIndicator") << QString("<div role='progressbar' aria-valuenow='77' aria-valuemin='22' aria-valuemax='99'></div>") << 0 << QAccessible::ProgressBar;
QTest::newRow("ax::mojom::Role::kRadioButton") << QString("<input type='radio'></input>") << 1 << QAccessible::RadioButton;
QTest::newRow("ax::mojom::Role::kRadioGroup") << QString("<fieldset role='radiogroup'></fieldset>") << 0 << QAccessible::Grouping;
QTest::newRow("ax::mojom::Role::kRegion") << QString("<div role='region'>a</div>") << 0 << QAccessible::Section;
- QTest::newRow("ax::mojom::Role::kRevision") << QString("<div role='revision'></div>") << 0 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kRow") << QString("<table role=table><tr><td>a</td></tr></table>") << 1 << QAccessible::Row;
QTest::newRow("ax::mojom::Role::kRowGroup") << QString("<table role=table><tbody role=rowgroup><tr><td>a</td></tr></tbody></table>") << 1 << QAccessible::Section;
QTest::newRow("ax::mojom::Role::kRowHeader") << QString("<table role=table><tr><th>a</td><td>b</td></tr></table>") << 2 << QAccessible::RowHeader;
- QTest::newRow("ax::mojom::Role::kRuby") << QString("<ruby>a</ruby>") << 1 << QAccessible::StaticText;
- QTest::newRow("ax::mojom::Role::kRubyAnnotation") << QString("<ruby><rt>a</rt></ruby>") << 2 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kRuby") << QString("<ruby>a</ruby>") << 1 << QAccessible::Grouping;
+ //QTest::newRow("ax::mojom::Role::kRubyAnnotation") // No mapping to ARIA role (presents as property on enclosing ruby element)
QTest::newRow("ax::mojom::Role::kScrollBar") << QString("<div role='scrollbar'>a</a>") << 0 << QAccessible::ScrollBar;
//QTest::newRow("ax::mojom::Role::kScrollView"); // No mapping to ARIA role
QTest::newRow("ax::mojom::Role::kSearch") << QString("<div role='search'>landmark</div>") << 0 << QAccessible::Section;
@@ -499,7 +502,7 @@ void tst_Accessibility::roles_data()
QTest::newRow("ax::mojom::Role::kStatus") << QString("<output>a</output>") << 1 << QAccessible::Indicator;
QTest::newRow("ax::mojom::Role::kStrong") << QString("<strong>a</strong>") << 1 << QAccessible::StaticText;
QTest::newRow("ax::mojom::Role::kSuggestion") << QString("<div role='suggestion'></div>") << 0 << QAccessible::Section;
- QTest::newRow("ax::mojom::Role::kSvgRoot") << QString("<svg width='10' height='10'></svg>") << 1 << QAccessible::Graphic;
+ QTest::newRow("ax::mojom::Role::kSvgRoot") << QString("<svg width='10' height='10'><text font-size='10'>SVG</text></svg>") << 1 << QAccessible::WebDocument;
QTest::newRow("ax::mojom::Role::kSwitch") << QString("<button aria-checked='false'>a</button>") << 1 << QAccessible::Button;
QTest::newRow("ax::mojom::Role::kTable") << QString("<table role=table><td>a</td></table>") << 0 << QAccessible::Table;
//QTest::newRow("ax::mojom::Role::kTableHeaderContainer"); // No mapping to ARIA role
@@ -528,10 +531,10 @@ void tst_Accessibility::roles()
QFETCH(QAccessible::Role, role);
QWebEngineView webView;
+ QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
webView.setHtml("<html><body>" + html + "</body></html>");
webView.show();
- QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
- QVERIFY(spyFinished.wait());
+ QTRY_COMPARE_WITH_TIMEOUT(spyFinished.size(), 1, 20000);
QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
@@ -541,7 +544,7 @@ void tst_Accessibility::roles()
return;
}
- QTRY_COMPARE(view->child(0)->childCount(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(view->child(0)->childCount(), 1, 20000);
QAccessibleInterface *document = view->child(0);
QAccessibleInterface *element = document->child(0);
@@ -553,9 +556,116 @@ void tst_Accessibility::roles()
QCOMPARE(element->role(), role);
}
+void tst_Accessibility::objectName()
+{
+ QWebEngineView webView;
+ QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
+ webView.setHtml("<html><body><p id='my_id'></p></body></html>");
+ webView.show();
+ QVERIFY(spyFinished.wait());
+ QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
+ QAccessibleInterface *document = view->child(0);
+ QTRY_COMPARE(document->childCount(), 1);
+ QAccessibleInterface *p = document->child(0);
+ QVERIFY(p);
+ QVERIFY(p->object());
+ QCOMPARE(p->role(), QAccessible::Paragraph);
+ QCOMPARE(p->object()->objectName(), QStringLiteral("my_id"));
+}
+
+void tst_Accessibility::crossTreeParent()
+{
+ QWebEngineView webView;
+ QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
+ webView.setHtml("<html><body><iframe src='data:text/html,<html><body><p id=my_id></p></body></html>'>Fallback text</iframe></body></html>");
+ webView.show();
+ QVERIFY(spyFinished.wait());
+ QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
+ QAccessibleInterface *document = view->child(0);
+ QCOMPARE(document->role(), QAccessible::WebDocument);
+ QTRY_COMPARE(document->childCount(), 1);
+ QAccessibleInterface *p = document->child(0);
+ QVERIFY(p);
+ QCOMPARE(p->parent(), document);
+ p = p->child(0);
+ QVERIFY(p);
+ QCOMPARE(p->role(), QAccessible::WebDocument);
+ QCOMPARE(p->parent()->parent(), document);
+ QTRY_COMPARE(p->childCount(), 1);
+ p = p->child(0);
+ QVERIFY(p);
+ QAccessibleInterface *subdocument = p;
+ QCOMPARE(p->role(), QAccessible::WebDocument);
+ QCOMPARE(p->parent()->parent()->parent(), document);
+ p = p->child(0);
+ QVERIFY(p);
+ QVERIFY(p->object());
+ QCOMPARE(p->role(), QAccessible::Paragraph);
+ QCOMPARE(p->parent(), subdocument);
+ QCOMPARE(p->parent()->parent()->parent()->parent(), document);
+ QCOMPARE(p->parent()->parent()->parent()->parent()->parent(), view);
+ QCOMPARE(p->object()->objectName(), QStringLiteral("my_id"));
+}
+
+void tst_Accessibility::tableCellInterface()
+{
+ QWebEngineView webView;
+ webView.resize(400, 400);
+ webView.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
+
+ QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
+ webView.setHtml(QLatin1String(
+ "<html><body>"
+ " <ul>"
+ " <li><a href='#link1' id='link1'>Link in ListItem</a></li>"
+ " </ul>"
+ ""
+ " <div role='rowgroup'>"
+ " <div role='row'>"
+ " <span role='cell'><a href='#link2' id='link2'>Link in Cell</a></span>"
+ " </div>"
+ " </div>"
+ "</body></html>"));
+ QTRY_COMPARE(spyFinished.size(), 1);
+
+ QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
+ QAccessibleInterface *document = view->child(0);
+ QTRY_COMPARE(document->childCount(), 2);
+
+ // ListItem without Table parent.
+ {
+ QAccessibleInterface *list = document->child(0);
+ QAccessibleInterface *listItem = list->child(0);
+ QVERIFY(!listItem->tableCellInterface());
+
+ // Should not crash.
+ QPoint linkCenter = elementCenter(webView.page(), QLatin1String("link1"));
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, linkCenter);
+ QTRY_COMPARE(webView.url().fragment(), QLatin1String("link1"));
+ }
+
+ // Cell without Table parent.
+ {
+ QAccessibleInterface *rowgroup = document->child(1);
+ QAccessibleInterface *row = rowgroup->child(0);
+ QAccessibleInterface *cell = row->child(0);
+ QVERIFY(!cell->tableCellInterface());
+
+ // Should not crash.
+ QPoint linkCenter = elementCenter(webView.page(), QLatin1String("link2"));
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, linkCenter);
+ QTRY_COMPARE(webView.url().fragment(), QLatin1String("link2"));
+ }
+}
+
static QByteArrayList params = QByteArrayList()
<< "--force-renderer-accessibility"
- << "--enable-features=AccessibilityExposeARIAAnnotations";
+ << "--enable-features=AccessibilityExposeARIAAnnotations"
+#if QT_CONFIG(webengine_embedded_build)
+ << "--disable-features=TimedHTMLParserBudget"
+#endif
+ ;
W_QTEST_MAIN(tst_Accessibility, params)
#include "tst_accessibility.moc"
diff --git a/tests/auto/widgets/certificateerror/certificateerror.pro b/tests/auto/widgets/certificateerror/certificateerror.pro
deleted file mode 100644
index 73ba7515b..000000000
--- a/tests/auto/widgets/certificateerror/certificateerror.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-include(../tests.pri)
-include(../../shared/https.pri)
-QT *= core-private
diff --git a/tests/auto/widgets/certificateerror/tst_certificateerror.cpp b/tests/auto/widgets/certificateerror/tst_certificateerror.cpp
deleted file mode 100644
index f11d9236c..000000000
--- a/tests/auto/widgets/certificateerror/tst_certificateerror.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <httpsserver.h>
-#include <util.h>
-
-#include <QWebEngineCertificateError>
-#include <QWebEnginePage>
-#include <QWebEngineSettings>
-
-#include <QtTest/QtTest>
-
-class tst_CertificateError : public QObject
-{
- Q_OBJECT
-public:
- tst_CertificateError() { }
-
-private Q_SLOTS:
- void handleError_data();
- void handleError();
-};
-
-struct PageWithCertificateErrorHandler : QWebEnginePage
-{
- PageWithCertificateErrorHandler(bool defer, bool accept, QObject *p = nullptr)
- : QWebEnginePage(p), deferError(defer), acceptCertificate(accept)
- , loadSpy(this, &QWebEnginePage::loadFinished) {
- }
-
- bool deferError, acceptCertificate;
-
- QSignalSpy loadSpy;
- QScopedPointer<QWebEngineCertificateError> error;
-
- bool certificateError(const QWebEngineCertificateError &e) override {
- error.reset(new QWebEngineCertificateError(e));
- if (deferError)
- error->defer();
- return acceptCertificate;
- }
-};
-
-void tst_CertificateError::handleError_data()
-{
- QTest::addColumn<bool>("deferError");
- QTest::addColumn<bool>("acceptCertificate");
- QTest::addColumn<QString>("expectedContent");
- QTest::addRow("Reject") << false << false << QString();
- QTest::addRow("DeferReject") << true << false << QString();
- QTest::addRow("DeferAccept") << true << true << "TEST";
-}
-
-void tst_CertificateError::handleError()
-{
- HttpsServer server;
- server.setExpectError(true);
- QVERIFY(server.start());
-
- connect(&server, &HttpsServer::newRequest, [&] (HttpReqRep *rr) {
- rr->setResponseBody(QByteArrayLiteral("<html><body>TEST</body></html>"));
- rr->sendResponse();
- });
-
- QFETCH(bool, deferError);
- QFETCH(bool, acceptCertificate);
- QFETCH(QString, expectedContent);
-
- PageWithCertificateErrorHandler page(deferError, acceptCertificate);
- page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
-
- page.setUrl(server.url());
- QTRY_VERIFY(page.error);
- QVERIFY(page.error->isOverridable());
- auto chain = page.error->certificateChain();
- QCOMPARE(chain.size(), 2);
- QCOMPARE(chain[0].serialNumber(), "3b:dd:1a:b7:2f:40:32:3b:c1:bf:37:d4:86:bd:56:c1:d0:6b:2a:43");
- QCOMPARE(chain[1].serialNumber(), "6d:52:fb:b4:57:3b:b2:03:c8:62:7b:7e:44:45:5c:d3:08:87:74:17");
-
- if (deferError) {
- QVERIFY(page.error->deferred());
- QVERIFY(!page.error->answered());
- QCOMPARE(page.loadSpy.count(), 0);
- QCOMPARE(toPlainTextSync(&page), QString());
-
- if (acceptCertificate)
- page.error->ignoreCertificateError();
- else
- page.error->rejectCertificate();
-
- QVERIFY(page.error->answered());
- page.error.reset();
- }
- QTRY_COMPARE_WITH_TIMEOUT(page.loadSpy.count(), 1, 30000);
- QCOMPARE(page.loadSpy.takeFirst().value(0).toBool(), acceptCertificate);
- QCOMPARE(toPlainTextSync(&page), expectedContent);
-}
-
-QTEST_MAIN(tst_CertificateError)
-#include <tst_certificateerror.moc>
diff --git a/tests/auto/widgets/defaultsurfaceformat/CMakeLists.txt b/tests/auto/widgets/defaultsurfaceformat/CMakeLists.txt
new file mode 100644
index 000000000..d95c1355b
--- /dev/null
+++ b/tests/auto/widgets/defaultsurfaceformat/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_defaultsurfaceformat
+ SOURCES
+ tst_defaultsurfaceformat.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+set(tst_defaultsurfaceformat_resource_files
+ "resources/index.html"
+)
+
+qt_internal_add_resource(tst_defaultsurfaceformat "tst_defaultsurfaceformat"
+ PREFIX
+ "/"
+ FILES
+ ${tst_defaultsurfaceformat_resource_files}
+)
diff --git a/tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro b/tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp
index 697ed3d08..c53f6f5b3 100644
--- a/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp
+++ b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp
@@ -1,33 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qtest.h>
-#include "../util.h"
+#include <util.h>
#include <QSurfaceFormat>
#include <QTimer>
diff --git a/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc
deleted file mode 100644
index 3d5f1b3b2..000000000
--- a/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/index.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/devtools/devtools.pro b/tests/auto/widgets/devtools/devtools.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/devtools/devtools.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/devtools/tst_devtools.cpp b/tests/auto/widgets/devtools/tst_devtools.cpp
deleted file mode 100644
index 3026b3931..000000000
--- a/tests/auto/widgets/devtools/tst_devtools.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-
-#include <qwebenginepage.h>
-
-class tst_DevTools : public QObject {
- Q_OBJECT
-
-private Q_SLOTS:
- void attachAndDestroyPageFirst();
- void attachAndDestroyInspectorFirst();
-};
-
-void tst_DevTools::attachAndDestroyPageFirst()
-{
- // External inspector + manual destruction of page first
- QWebEnginePage* page = new QWebEnginePage();
- QWebEnginePage* inspector = new QWebEnginePage();
-
- QSignalSpy spy(page, &QWebEnginePage::loadFinished);
- page->load(QUrl("data:text/plain,foobarbaz"));
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000);
-
- inspector->setInspectedPage(page);
- page->triggerAction(QWebEnginePage::InspectElement);
-
- // This is deliberately racy:
- QTest::qWait(10);
-
- delete page;
- delete inspector;
-}
-
-void tst_DevTools::attachAndDestroyInspectorFirst()
-{
- // External inspector + manual destruction of inspector first
- QWebEnginePage* page = new QWebEnginePage();
- QWebEnginePage* inspector = new QWebEnginePage();
- inspector->setInspectedPage(page);
-
- QSignalSpy spy(page, &QWebEnginePage::loadFinished);
- page->setHtml(QStringLiteral("<body><h1>FOO BAR!</h1></body>"));
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000);
-
- page->triggerAction(QWebEnginePage::InspectElement);
-
- delete inspector;
-
- page->triggerAction(QWebEnginePage::InspectElement);
-
- // This is deliberately racy:
- QTest::qWait(10);
-
- delete page;
-}
-
-
-QTEST_MAIN(tst_DevTools)
-
-#include "tst_devtools.moc"
diff --git a/tests/auto/widgets/favicon/CMakeLists.txt b/tests/auto/widgets/favicon/CMakeLists.txt
new file mode 100644
index 000000000..0deae6a37
--- /dev/null
+++ b/tests/auto/widgets/favicon/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_favicon
+ SOURCES
+ tst_favicon.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+set(tst_favicon_resource_files
+ "resources/favicon-misc.html"
+ "resources/favicon-multi.html"
+ "resources/favicon-shortcut.html"
+ "resources/favicon-single.html"
+ "resources/favicon-touch.html"
+ "resources/favicon-unavailable.html"
+ "resources/icons/qt144.png"
+ "resources/icons/qt32.ico"
+ "resources/icons/qtmulti.ico"
+ "resources/test1.html"
+)
+
+qt_internal_add_resource(tst_favicon "tst_favicon"
+ PREFIX
+ "/"
+ FILES
+ ${tst_favicon_resource_files}
+)
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-misc.html b/tests/auto/widgets/favicon/resources/favicon-misc.html
index 9e788bdf4..ea587886f 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-misc.html
+++ b/tests/auto/widgets/favicon/resources/favicon-misc.html
@@ -1,8 +1,8 @@
<html>
<head>
<title>Favicon Test</title>
- <link rel="shortcut icon" href="icons/qt32.ico" />
- <link rel="apple-touch-icon" href="icons/qt144.png" />
+ <link rel="shortcut icon" href="icons/qt32.ico" sizes="32x32" />
+ <link rel="apple-touch-icon" href="icons/qt144.png" sizes="144x144" />
<link rel="shortcut icon" href="icons/unavailable.ico" />
</head>
<body>
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-multi.html b/tests/auto/widgets/favicon/resources/favicon-multi.html
index cc5f3fd66..56eeca8c4 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-multi.html
+++ b/tests/auto/widgets/favicon/resources/favicon-multi.html
@@ -1,7 +1,7 @@
<html>
<head>
<title>Multi-sized Favicon Test</title>
- <link rel="shortcut icon" sizes="16x16 32x23 64x64" href="icons/qtmulti.ico" />
+ <link rel="shortcut icon" sizes="16x16 32x32 64x64" href="icons/qtmulti.ico" />
</head>
<body>
<h1>Multi-sized Favicon Test</h1>
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html b/tests/auto/widgets/favicon/resources/favicon-shortcut.html
index 786cdb816..786cdb816 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html
+++ b/tests/auto/widgets/favicon/resources/favicon-shortcut.html
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-single.html b/tests/auto/widgets/favicon/resources/favicon-single.html
index eb4675c75..eb4675c75 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-single.html
+++ b/tests/auto/widgets/favicon/resources/favicon-single.html
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-touch.html b/tests/auto/widgets/favicon/resources/favicon-touch.html
index 271783434..271783434 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-touch.html
+++ b/tests/auto/widgets/favicon/resources/favicon-touch.html
diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html b/tests/auto/widgets/favicon/resources/favicon-unavailable.html
index c45664294..c45664294 100644
--- a/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html
+++ b/tests/auto/widgets/favicon/resources/favicon-unavailable.html
diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qt144.png b/tests/auto/widgets/favicon/resources/icons/qt144.png
index 050b1e066..050b1e066 100644
--- a/tests/auto/widgets/faviconmanager/resources/icons/qt144.png
+++ b/tests/auto/widgets/favicon/resources/icons/qt144.png
Binary files differ
diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico b/tests/auto/widgets/favicon/resources/icons/qt32.ico
index 2f6fcb5bc..2f6fcb5bc 100644
--- a/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico
+++ b/tests/auto/widgets/favicon/resources/icons/qt32.ico
Binary files differ
diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico b/tests/auto/widgets/favicon/resources/icons/qtmulti.ico
index 81e5a22e8..81e5a22e8 100644
--- a/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico
+++ b/tests/auto/widgets/favicon/resources/icons/qtmulti.ico
Binary files differ
diff --git a/tests/auto/widgets/faviconmanager/resources/test1.html b/tests/auto/widgets/favicon/resources/test1.html
index b323f966e..b323f966e 100644
--- a/tests/auto/widgets/faviconmanager/resources/test1.html
+++ b/tests/auto/widgets/favicon/resources/test1.html
diff --git a/tests/auto/widgets/favicon/tst_favicon.cpp b/tests/auto/widgets/favicon/tst_favicon.cpp
new file mode 100644
index 000000000..c70aa1182
--- /dev/null
+++ b/tests/auto/widgets/favicon/tst_favicon.cpp
@@ -0,0 +1,869 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QtTest/QtTest>
+#include <util.h>
+
+#include <QWebEngineHistory>
+#include <QWebEnginePage>
+#include <QWebEngineProfile>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+
+class tst_Favicon : public QObject
+{
+ Q_OBJECT
+
+public Q_SLOTS:
+ void init();
+ void initTestCase();
+ void cleanupTestCase();
+ void cleanup();
+
+private Q_SLOTS:
+ void faviconLoad();
+ void faviconLoadFromResources();
+ void faviconLoadEncodedUrl();
+ void faviconLoadAfterHistoryNavigation();
+ void faviconLoadPushState();
+ void noFavicon();
+ void aboutBlank();
+ void unavailableFavicon();
+ void errorPageEnabled();
+ void errorPageDisabled();
+ void touchIcon();
+ void multiIcon();
+ void downloadIconsDisabled_data();
+ void downloadIconsDisabled();
+ void downloadTouchIconsEnabled_data();
+ void downloadTouchIconsEnabled();
+ void dynamicFavicon();
+ void touchIconWithSameURL();
+
+ void iconDatabaseOTR();
+ void requestIconForIconURL_data();
+ void requestIconForIconURL();
+ void requestIconForPageURL_data();
+ void requestIconForPageURL();
+ void desiredSize();
+
+private:
+ QWebEngineView *m_view;
+ QWebEnginePage *m_page;
+ QWebEngineProfile *m_profile;
+};
+
+void tst_Favicon::init()
+{
+ m_profile = new QWebEngineProfile(this);
+ m_view = new QWebEngineView();
+ m_page = new QWebEnginePage(m_profile, m_view);
+ m_view->setPage(m_page);
+}
+
+void tst_Favicon::initTestCase() { }
+
+void tst_Favicon::cleanupTestCase() { }
+
+void tst_Favicon::cleanup()
+{
+ delete m_view;
+ delete m_profile;
+}
+
+void tst_Favicon::faviconLoad()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/favicon-single.html"));
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(iconUrl, m_page->iconUrl());
+ QCOMPARE(iconUrl,
+ QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/icons/qt32.ico")));
+
+ const QIcon &icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+
+ QCOMPARE(icon.availableSizes().size(), 2);
+ QVERIFY(icon.availableSizes().contains(QSize(16, 16)));
+ QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
+}
+
+void tst_Favicon::faviconLoadFromResources()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url("qrc:/resources/favicon-single.html");
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(iconUrl, m_page->iconUrl());
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico"));
+
+ const QIcon &icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+
+ QCOMPARE(icon.availableSizes().size(), 2);
+ QVERIFY(icon.availableSizes().contains(QSize(16, 16)));
+ QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
+}
+
+void tst_Favicon::faviconLoadEncodedUrl()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QString urlString = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/favicon-single.html"))
+ .toString();
+ QUrl url(urlString + QLatin1String("?favicon=load should work with#whitespace!"));
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(m_page->iconUrl(), iconUrl);
+ QCOMPARE(iconUrl,
+ QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/icons/qt32.ico")));
+
+ const QIcon &icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+
+ QCOMPARE(icon.availableSizes().size(), 2);
+ QVERIFY(icon.availableSizes().contains(QSize(16, 16)));
+ QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
+}
+
+void tst_Favicon::faviconLoadAfterHistoryNavigation()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ m_page->load(QUrl("qrc:/resources/favicon-single.html"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+ QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico"));
+
+ m_page->load(QUrl("qrc:/resources/favicon-multi.html"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 3);
+ QTRY_COMPARE(iconChangedSpy.size(), 3);
+ QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qtmulti.ico"));
+
+ m_page->triggerAction(QWebEnginePage::Back);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 3, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 5);
+ QTRY_COMPARE(iconChangedSpy.size(), 5);
+ QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico"));
+
+ m_page->triggerAction(QWebEnginePage::Forward);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 4, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 7);
+ QTRY_COMPARE(iconChangedSpy.size(), 7);
+ QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qtmulti.ico"));
+}
+
+void tst_Favicon::faviconLoadPushState()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url("qrc:/resources/favicon-single.html");
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(iconUrl, m_page->iconUrl());
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico"));
+
+ const QIcon &icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+
+ iconUrlChangedSpy.clear();
+ iconChangedSpy.clear();
+
+ // pushState() is a same document navigation and should not reset or
+ // update favicon.
+ QCOMPARE(m_page->history()->count(), 1);
+ evaluateJavaScriptSync(m_page, "history.pushState('', '')");
+ QTRY_COMPARE(m_page->history()->count(), 2);
+
+ // Favicon change is not expected.
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+ QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico"));
+}
+
+void tst_Favicon::noFavicon()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/test1.html"));
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::aboutBlank()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url("about:blank");
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::unavailableFavicon()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/favicon-unavailable.html"));
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::errorPageEnabled()
+{
+ m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url("http://url.invalid");
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::errorPageDisabled()
+{
+ m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url("http://url.invalid");
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::touchIcon()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/favicon-touch.html"));
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::multiIcon()
+{
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/favicon-multi.html"));
+ QUrl iconUrl;
+ QIcon icon;
+
+ // If touch icons are disabled, the favicon is provided in two sizes (16x16 and 32x32) according
+ // to the supported scale factors (100P, 200P).
+ m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false);
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(m_page->iconUrl(), iconUrl);
+ QCOMPARE(iconUrl,
+ QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/icons/qtmulti.ico")));
+
+ icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+ QCOMPARE(icon.availableSizes().size(), 2);
+ QVERIFY(icon.availableSizes().contains(QSize(16, 16)));
+ QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
+
+ // Reset
+ loadFinishedSpy.clear();
+ m_page->load(QUrl("about:blank"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ iconUrlChangedSpy.clear();
+ iconChangedSpy.clear();
+ loadFinishedSpy.clear();
+ icon = QIcon();
+
+ // If touch icons are enabled, the largest icon is provided.
+ m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, true);
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(m_page->iconUrl(), iconUrl);
+ QCOMPARE(iconUrl,
+ QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()
+ + QLatin1String("/resources/icons/qtmulti.ico")));
+
+ icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+ QCOMPARE(icon.availableSizes().size(), 1);
+ QVERIFY(icon.availableSizes().contains(QSize(64, 64)));
+}
+
+void tst_Favicon::downloadIconsDisabled_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html");
+ QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html");
+ QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html");
+ QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html");
+ QTest::newRow("unavailable") << QUrl("qrc:/resources/favicon-unavailable.html");
+}
+
+void tst_Favicon::downloadIconsDisabled()
+{
+ QFETCH(QUrl, url);
+
+ m_page->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QCOMPARE(iconUrlChangedSpy.size(), 0);
+ QCOMPARE(iconChangedSpy.size(), 0);
+
+ QVERIFY(m_page->iconUrl().isEmpty());
+ QVERIFY(m_page->icon().isNull());
+}
+
+void tst_Favicon::downloadTouchIconsEnabled_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QUrl>("expectedIconUrl");
+ QTest::addColumn<QSize>("expectedIconSize");
+ QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html")
+ << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
+ QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html")
+ << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
+ QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html")
+ << QUrl("qrc:/resources/icons/qt32.ico") << QSize(32, 32);
+ QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html")
+ << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
+}
+
+void tst_Favicon::downloadTouchIconsEnabled()
+{
+ QFETCH(QUrl, url);
+ QFETCH(QUrl, expectedIconUrl);
+ QFETCH(QSize, expectedIconSize);
+
+ m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, true);
+
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ m_page->load(url);
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ const QUrl &iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
+ QCOMPARE(m_page->iconUrl(), iconUrl);
+ QCOMPARE(iconUrl, expectedIconUrl);
+
+ const QIcon &icon = m_page->icon();
+ QVERIFY(!icon.isNull());
+
+ QCOMPARE(icon.availableSizes().size(), 1);
+ QCOMPARE(icon.availableSizes().first(), expectedIconSize);
+}
+
+void tst_Favicon::dynamicFavicon()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QMap<Qt::GlobalColor, QString> colors;
+ colors.insert(Qt::red,
+ QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="));
+ colors.insert(Qt::green,
+ QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg=="));
+ colors.insert(Qt::blue,
+ QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg=="));
+
+ m_page->setHtml("<html>"
+ "<link rel='icon' type='image/png' "
+ "href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>"
+ "</html>");
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(Qt::black));
+
+ for (Qt::GlobalColor color : colors.keys()) {
+ iconChangedSpy.clear();
+ evaluateJavaScriptSync(
+ m_page,
+ "document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[color] + "';");
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+ QTRY_COMPARE(m_page->iconUrl().toString(),
+ QString("data:image/png;base64," + colors[color]));
+ QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(color));
+ }
+}
+
+void tst_Favicon::touchIconWithSameURL()
+{
+ m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false);
+
+ const QString icon("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=");
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ m_page->setHtml("<html>"
+ "<link rel='icon' type='image/png' href='" + icon + "'/>"
+ "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>"
+ "</html>");
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 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(iconUrlChangedSpy.size(), 1);
+ QCOMPARE(m_page->iconUrl().toString(), icon);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ loadFinishedSpy.clear();
+ iconUrlChangedSpy.clear();
+ iconChangedSpy.clear();
+
+ m_page->setHtml("<html>"
+ "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>"
+ "</html>");
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+
+ // This page only has a touch icon. With disabled touch icons we don't expect any icon to be
+ // shown even if the same icon was loaded previously.
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QVERIFY(m_page->iconUrl().toString().isEmpty());
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+}
+
+void tst_Favicon::iconDatabaseOTR()
+{
+ QWebEngineProfile profile;
+ QWebEngineView view;
+ QWebEnginePage *page = new QWebEnginePage(&profile, &view);
+ view.setPage(page);
+
+ QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(page, SIGNAL(iconChanged(QIcon)));
+
+ page->load(QUrl("qrc:/resources/favicon-misc.html"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForIconURL(page->iconUrl(), 0,
+ [page, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl) {
+ QVERIFY(icon.isNull());
+ QCOMPARE(iconUrl, page->iconUrl());
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForPageURL(page->url(), 0,
+ [page, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl, const QUrl &pageUrl) {
+ QVERIFY(icon.isNull());
+ QVERIFY(iconUrl.isEmpty());
+ QCOMPARE(pageUrl, page->url());
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+}
+
+void tst_Favicon::requestIconForIconURL_data()
+{
+ QTest::addColumn<bool>("touchIconsEnabled");
+ QTest::newRow("touch icons enabled") << true;
+ QTest::newRow("touch icons disabled") << false;
+}
+
+void tst_Favicon::requestIconForIconURL()
+{
+ QFETCH(bool, touchIconsEnabled);
+
+ QTemporaryDir tmpDir;
+ QWebEngineProfile profile("iconDatabase-iconurl");
+ profile.setPersistentStoragePath(tmpDir.path());
+ profile.settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+ profile.settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, touchIconsEnabled);
+
+ QWebEngineView view;
+ QWebEnginePage *page = new QWebEnginePage(&profile, &view);
+ view.setPage(page);
+
+ QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(page, SIGNAL(iconChanged(QIcon)));
+
+ page->load(QUrl("qrc:/resources/favicon-misc.html"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ page->load(QUrl("about:blank"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 2);
+ QTRY_COMPARE(iconChangedSpy.size(), 2);
+ QVERIFY(page->icon().isNull());
+ QVERIFY(page->iconUrl().isEmpty());
+
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForIconURL(QUrl("qrc:/resources/icons/qt144.png"), 0,
+ [touchIconsEnabled, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl) {
+ if (touchIconsEnabled) {
+ QVERIFY(!icon.isNull());
+ QCOMPARE(icon.pixmap(QSize(32, 32), 1.0).toImage().pixel(16, 16), 0xfff2f9ec);
+ } else {
+ QVERIFY(icon.isNull());
+ }
+
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt144.png"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForIconURL(QUrl("qrc:/resources/icons/qt32.ico"), 0,
+ [&iconRequestDone](const QIcon &icon, const QUrl &iconUrl) {
+ QVERIFY(!icon.isNull());
+ QCOMPARE(icon.pixmap(QSize(32, 32), 1.0).toImage().pixel(16, 16), 0xffeef7e6);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+}
+
+void tst_Favicon::requestIconForPageURL_data()
+{
+ QTest::addColumn<bool>("touchIconsEnabled");
+ QTest::newRow("touch icons enabled") << true;
+ QTest::newRow("touch icons disabled") << false;
+}
+
+void tst_Favicon::requestIconForPageURL()
+{
+ QFETCH(bool, touchIconsEnabled);
+
+ QTemporaryDir tmpDir;
+ QWebEngineProfile profile("iconDatabase-pageurl");
+ profile.setPersistentStoragePath(tmpDir.path());
+ profile.settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+ profile.settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, touchIconsEnabled);
+
+
+ QWebEngineView view;
+ QWebEnginePage *page = new QWebEnginePage(&profile, &view);
+ view.setPage(page);
+
+ QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(page, SIGNAL(iconChanged(QIcon)));
+
+ page->load(QUrl("qrc:/resources/favicon-misc.html"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ page->load(QUrl("about:blank"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 2);
+ QTRY_COMPARE(iconChangedSpy.size(), 2);
+ QVERIFY(page->icon().isNull());
+ QVERIFY(page->iconUrl().isEmpty());
+
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForPageURL(QUrl("qrc:/resources/favicon-misc.html"), 0,
+ [touchIconsEnabled, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl, const QUrl &pageUrl) {
+ QVERIFY(!icon.isNull());
+ if (touchIconsEnabled) {
+ QCOMPARE(icon.pixmap(QSize(32, 32), 1.0).toImage().pixel(16, 16), 0xfff2f9ec);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt144.png"));
+ } else {
+ QCOMPARE(icon.pixmap(QSize(32, 32), 1.0).toImage().pixel(16, 16), 0xffeef7e6);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico"));
+ }
+
+ QCOMPARE(pageUrl, QUrl("qrc:/resources/favicon-misc.html"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+}
+
+void tst_Favicon::desiredSize()
+{
+ QTemporaryDir tmpDir;
+ QWebEngineProfile profile("iconDatabase-desiredsize");
+ profile.setPersistentStoragePath(tmpDir.path());
+ profile.settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+
+ QWebEngineView view;
+ QWebEnginePage *page = new QWebEnginePage(&profile, &view);
+ view.setPage(page);
+
+ // Disable touch icons: icon with size 16x16 will be loaded.
+ {
+ profile.settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false);
+
+ QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(page, SIGNAL(iconChanged(QIcon)));
+
+ page->load(QUrl("qrc:/resources/favicon-multi.html"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ page->load(QUrl("about:blank"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 2);
+ QTRY_COMPARE(iconChangedSpy.size(), 2);
+ QVERIFY(page->icon().isNull());
+ QVERIFY(page->iconUrl().isEmpty());
+ }
+
+ int desiredSizeInPixel = 16;
+ QRgb expectedPixel = 0xfffdfefc;
+
+ // Request icon with size 16x16 (desiredSizeInPixel).
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForPageURL(QUrl("qrc:/resources/favicon-multi.html"), desiredSizeInPixel,
+ [desiredSizeInPixel, expectedPixel, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl, const QUrl &pageUrl) {
+ QVERIFY(!icon.isNull());
+ QRgb pixel = icon.pixmap(QSize(desiredSizeInPixel, desiredSizeInPixel), 1.0)
+ .toImage()
+ .pixel(8, 8);
+ QCOMPARE(pixel, expectedPixel);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qtmulti.ico"));
+ QCOMPARE(pageUrl, QUrl("qrc:/resources/favicon-multi.html"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+
+ // Enable touch icons: icon with the largest size (64x64) will be loaded.
+ {
+ profile.settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, true);
+
+ QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(page, SIGNAL(iconChanged(QIcon)));
+
+ page->load(QUrl("qrc:/resources/favicon-multi.html"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 1);
+ QTRY_COMPARE(iconChangedSpy.size(), 1);
+
+ page->load(QUrl("about:blank"));
+
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
+ QTRY_COMPARE(iconUrlChangedSpy.size(), 2);
+ QTRY_COMPARE(iconChangedSpy.size(), 2);
+ QVERIFY(page->icon().isNull());
+ QVERIFY(page->iconUrl().isEmpty());
+ }
+
+ // Request icon with size 16x16.
+ // The icon is stored with two sizes in the database. This request should result same pixel
+ // as the first one.
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForPageURL(QUrl("qrc:/resources/favicon-multi.html"), desiredSizeInPixel,
+ [desiredSizeInPixel, expectedPixel, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl, const QUrl &pageUrl) {
+ QVERIFY(!icon.isNull());
+ QRgb pixel = icon.pixmap(QSize(desiredSizeInPixel, desiredSizeInPixel), 1.0)
+ .toImage()
+ .pixel(8, 8);
+ QCOMPARE(pixel, expectedPixel);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qtmulti.ico"));
+ QCOMPARE(pageUrl, QUrl("qrc:/resources/favicon-multi.html"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+
+ // Request icon with size 64x64.
+ // This requests the another size from the database. The pixel should differ.
+ {
+ bool iconRequestDone = false;
+ profile.requestIconForPageURL(QUrl("qrc:/resources/favicon-multi.html"), 64,
+ [desiredSizeInPixel, expectedPixel, &iconRequestDone](const QIcon &icon, const QUrl &iconUrl, const QUrl &pageUrl) {
+ QVERIFY(!icon.isNull());
+ QRgb pixel = icon.pixmap(QSize(desiredSizeInPixel, desiredSizeInPixel), 1.0)
+ .toImage()
+ .pixel(8, 8);
+ QVERIFY(pixel != expectedPixel);
+ QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qtmulti.ico"));
+ QCOMPARE(pageUrl, QUrl("qrc:/resources/favicon-multi.html"));
+ iconRequestDone = true;
+ });
+ QTRY_VERIFY(iconRequestDone);
+ }
+}
+
+QTEST_MAIN(tst_Favicon)
+
+#include "tst_favicon.moc"
diff --git a/tests/auto/widgets/faviconmanager/faviconmanager.pro b/tests/auto/widgets/faviconmanager/faviconmanager.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/faviconmanager/faviconmanager.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp
deleted file mode 100644
index 46038cdc6..000000000
--- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp
+++ /dev/null
@@ -1,551 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-#include "../util.h"
-
-#include <qwebenginepage.h>
-#include <qwebengineprofile.h>
-#include <qwebenginesettings.h>
-#include <qwebengineview.h>
-
-
-class tst_FaviconManager : public QObject {
- Q_OBJECT
-
-public Q_SLOTS:
- void init();
- void initTestCase();
- void cleanupTestCase();
- void cleanup();
-
-private Q_SLOTS:
- void faviconLoad();
- void faviconLoadFromResources();
- void faviconLoadEncodedUrl();
- void noFavicon();
- void aboutBlank();
- void unavailableFavicon();
- void errorPageEnabled();
- void errorPageDisabled();
- void bestFavicon();
- void touchIcon();
- void multiIcon();
- void candidateIcon();
- void downloadIconsDisabled_data();
- void downloadIconsDisabled();
- void downloadTouchIconsEnabled_data();
- void downloadTouchIconsEnabled();
- void dynamicFavicon();
- void touchIconWithSameURL();
-
-private:
- QWebEngineView *m_view;
- QWebEnginePage *m_page;
- QWebEngineProfile *m_profile;
-};
-
-
-void tst_FaviconManager::init()
-{
- m_profile = new QWebEngineProfile(this);
- m_view = new QWebEngineView();
- m_page = new QWebEnginePage(m_profile, m_view);
- m_view->setPage(m_page);
-}
-
-
-void tst_FaviconManager::initTestCase()
-{
-}
-
-void tst_FaviconManager::cleanupTestCase()
-{
-}
-
-
-void tst_FaviconManager::cleanup()
-{
- delete m_view;
- delete m_profile;
-}
-
-void tst_FaviconManager::faviconLoad()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-single.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(iconUrl, m_page->iconUrl());
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico")));
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QCOMPARE(icon.availableSizes().count(), 1);
- QSize iconSize = icon.availableSizes().first();
- QCOMPARE(iconSize, QSize(32, 32));
-}
-
-void tst_FaviconManager::faviconLoadFromResources()
-{
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url("qrc:/resources/favicon-single.html");
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(iconUrl, m_page->iconUrl());
- QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico"));
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QCOMPARE(icon.availableSizes().count(), 1);
- QSize iconSize = icon.availableSizes().first();
- QCOMPARE(iconSize, QSize(32, 32));
-}
-
-void tst_FaviconManager::faviconLoadEncodedUrl()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QString urlString = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-single.html")).toString();
- QUrl url(urlString + QLatin1String("?favicon=load should work with#whitespace!"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(m_page->iconUrl(), iconUrl);
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico")));
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QCOMPARE(icon.availableSizes().count(), 1);
- QSize iconSize = icon.availableSizes().first();
- QCOMPARE(iconSize, QSize(32, 32));
-}
-
-void tst_FaviconManager::noFavicon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/test1.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::aboutBlank()
-{
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url("about:blank");
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::unavailableFavicon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-unavailable.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::errorPageEnabled()
-{
- m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url("http://url.invalid");
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::errorPageDisabled()
-{
- m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url("http://url.invalid");
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::bestFavicon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url, iconUrl;
- QIcon icon;
- QSize iconSize;
-
- url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-misc.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(iconUrl, m_page->iconUrl());
- // Touch icon is ignored
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico")));
-
- icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QCOMPARE(icon.availableSizes().count(), 1);
- iconSize = icon.availableSizes().first();
- QCOMPARE(iconSize, QSize(32, 32));
-
- loadFinishedSpy.clear();
- iconUrlChangedSpy.clear();
- iconChangedSpy.clear();
-
- url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-shortcut.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_VERIFY(iconUrlChangedSpy.count() >= 1);
- QTRY_VERIFY(iconChangedSpy.count() >= 1);
-
- iconUrl = iconUrlChangedSpy.last().at(0).toString();
-
- // If the icon URL is empty we have to wait for
- // the second iconChanged signal that propagates the expected URL
- if (iconUrl.isEmpty()) {
- QTRY_COMPARE(iconUrlChangedSpy.count(), 2);
- QTRY_COMPARE(iconChangedSpy.count(), 2);
- iconUrl = iconUrlChangedSpy.last().at(0).toString();
- }
-
- QCOMPARE(iconUrl, m_page->iconUrl());
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt144.png")));
-
- icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QVERIFY(icon.availableSizes().count() >= 1);
- QVERIFY(icon.availableSizes().contains(QSize(144, 144)));
-}
-
-void tst_FaviconManager::touchIcon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-touch.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::multiIcon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-multi.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(m_page->iconUrl(), iconUrl);
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qtmulti.ico")));
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
- QCOMPARE(icon.availableSizes().count(), 3);
- QVERIFY(icon.availableSizes().contains(QSize(16, 16)));
- QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
- QVERIFY(icon.availableSizes().contains(QSize(64, 64)));
-}
-
-void tst_FaviconManager::candidateIcon()
-{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-shortcut.html"));
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(m_page->iconUrl(), iconUrl);
- QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt144.png")));
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
- QCOMPARE(icon.availableSizes().count(), 2);
- QVERIFY(icon.availableSizes().contains(QSize(32, 32)));
- QVERIFY(icon.availableSizes().contains(QSize(144, 144)));
-}
-
-void tst_FaviconManager::downloadIconsDisabled_data()
-{
- QTest::addColumn<QUrl>("url");
- QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html");
- QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html");
- QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html");
- QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html");
- QTest::newRow("unavailable") << QUrl("qrc:/resources/favicon-unavailable.html");
-}
-
-void tst_FaviconManager::downloadIconsDisabled()
-{
- QFETCH(QUrl, url);
-
- m_page->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QCOMPARE(iconUrlChangedSpy.count(), 0);
- QCOMPARE(iconChangedSpy.count(), 0);
-
- QVERIFY(m_page->iconUrl().isEmpty());
- QVERIFY(m_page->icon().isNull());
-}
-
-void tst_FaviconManager::downloadTouchIconsEnabled_data()
-{
- QTest::addColumn<QUrl>("url");
- QTest::addColumn<QUrl>("expectedIconUrl");
- QTest::addColumn<QSize>("expectedIconSize");
- QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
- QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
- QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html") << QUrl("qrc:/resources/icons/qt32.ico") << QSize(32, 32);
- QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144);
-}
-
-void tst_FaviconManager::downloadTouchIconsEnabled()
-{
- QFETCH(QUrl, url);
- QFETCH(QUrl, expectedIconUrl);
- QFETCH(QSize, expectedIconSize);
-
- m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, true);
-
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- m_page->load(url);
-
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- const QUrl &iconUrl = iconUrlChangedSpy.at(0).at(0).toString();
- QCOMPARE(m_page->iconUrl(), iconUrl);
- QCOMPARE(iconUrl, expectedIconUrl);
-
- const QIcon &icon = m_page->icon();
- QVERIFY(!icon.isNull());
-
- QVERIFY(icon.availableSizes().count() >= 1);
- QVERIFY(icon.availableSizes().contains(expectedIconSize));
-}
-
-void tst_FaviconManager::dynamicFavicon()
-{
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- QMap<Qt::GlobalColor, QString> colors;
- colors.insert(Qt::red, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="));
- colors.insert(Qt::green, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg=="));
- colors.insert(Qt::blue, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg=="));
-
- m_page->setHtml("<html>"
- "<link rel='icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>"
- "</html>");
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(Qt::black));
-
- for (Qt::GlobalColor color : colors.keys()) {
- iconChangedSpy.clear();
- evaluateJavaScriptSync(m_page, "document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[color] + "';");
- QTRY_COMPARE(iconChangedSpy.count(), 1);
- QTRY_COMPARE(m_page->iconUrl().toString(), QString("data:image/png;base64," + colors[color]));
- QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(color));
- }
-}
-
-void tst_FaviconManager::touchIconWithSameURL()
-{
- m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false);
-
- const QString icon("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=");
- QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
- QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
- QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
-
- m_page->setHtml("<html>"
- "<link rel='icon' type='image/png' href='" + icon + "'/>"
- "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>"
- "</html>");
- 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(iconUrlChangedSpy.count(), 1);
- QCOMPARE(m_page->iconUrl().toString(), icon);
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
- loadFinishedSpy.clear();
- iconUrlChangedSpy.clear();
- iconChangedSpy.clear();
-
- m_page->setHtml("<html>"
- "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>"
- "</html>");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
-
- // This page only has a touch icon. With disabled touch icons we don't expect any icon to be shown even if the same icon
- // was loaded previously.
- QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
- QVERIFY(m_page->iconUrl().toString().isEmpty());
- QTRY_COMPARE(iconChangedSpy.count(), 1);
-
-}
-
-QTEST_MAIN(tst_FaviconManager)
-
-#include "tst_faviconmanager.moc"
diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc b/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc
deleted file mode 100644
index a352f8a83..000000000
--- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/favicon-misc.html</file>
- <file>resources/favicon-multi.html</file>
- <file>resources/favicon-shortcut.html</file>
- <file>resources/favicon-single.html</file>
- <file>resources/favicon-touch.html</file>
- <file>resources/favicon-unavailable.html</file>
- <file>resources/icons/qt144.png</file>
- <file>resources/icons/qt32.ico</file>
- <file>resources/icons/qtmulti.ico</file>
- <file>resources/test1.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/loadsignals/BLACKLIST b/tests/auto/widgets/loadsignals/BLACKLIST
deleted file mode 100644
index 570666a83..000000000
--- a/tests/auto/widgets/loadsignals/BLACKLIST
+++ /dev/null
@@ -1,14 +0,0 @@
-[secondLoadForError_WhenErrorPageEnabled:ErrorPageEnabled]
-*
-
-# QTBUG-65223
-[loadStartedAndFinishedCount:WithAnchorClickedFromJS]
-*
-
-# QTBUG-66869 (https://codereview.qt-project.org/#/c/222112/ is only a workaround)
-[loadAfterInPageNavigation_qtbug66869]
-*
-
-# QTBUG-66661
-[fileDownloadDoesNotTriggerLoadSignals_qtbug66661]
-*
diff --git a/tests/auto/widgets/loadsignals/CMakeLists.txt b/tests/auto/widgets/loadsignals/CMakeLists.txt
new file mode 100644
index 000000000..bbd0387d9
--- /dev/null
+++ b/tests/auto/widgets/loadsignals/CMakeLists.txt
@@ -0,0 +1,63 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_loadsignals
+ SOURCES
+ tst_loadsignals.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::HttpServer
+ Test::Util
+)
+
+get_target_property(sharedData Test::HttpServer SHARED_DATA)
+
+set_source_files_properties("${sharedData}/loadprogress/downloadable.tar.gz"
+ PROPERTIES QT_RESOURCE_ALIAS "downloadable.tar.gz"
+)
+set_source_files_properties("${sharedData}/loadprogress/page1.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page1.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page2.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page2.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page3.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page3.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page4.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page4.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page5.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page5.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page6.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page6.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page7.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page7.html"
+)
+set_source_files_properties("${sharedData}/loadprogress/page8.html"
+ PROPERTIES QT_RESOURCE_ALIAS "page8.html"
+)
+
+set(tst_loadsignals_resource_files
+ "${sharedData}/loadprogress/downloadable.tar.gz"
+ "${sharedData}/loadprogress/page1.html"
+ "${sharedData}/loadprogress/page2.html"
+ "${sharedData}/loadprogress/page3.html"
+ "${sharedData}/loadprogress/page4.html"
+ "${sharedData}/loadprogress/page5.html"
+ "${sharedData}/loadprogress/page6.html"
+ "${sharedData}/loadprogress/page7.html"
+ "${sharedData}/loadprogress/page8.html"
+)
+
+qt_internal_add_resource(tst_loadsignals "tst_loadsignals"
+ PREFIX
+ "/resources"
+ FILES
+ ${tst_loadsignals_resource_files}
+)
diff --git a/tests/auto/widgets/loadsignals/loadsignals.pro b/tests/auto/widgets/loadsignals/loadsignals.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/loadsignals/loadsignals.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz b/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz
deleted file mode 100644
index 741cb8ca6..000000000
--- a/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/loadsignals/resources/page1.html b/tests/auto/widgets/loadsignals/resources/page1.html
deleted file mode 100644
index 5cd479ab6..000000000
--- a/tests/auto/widgets/loadsignals/resources/page1.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
- <head>
- <title>page1</title>
- </head>
- <body>
- <h1>page1</h1>
- </body>
-</html>
diff --git a/tests/auto/widgets/loadsignals/resources/page2.html b/tests/auto/widgets/loadsignals/resources/page2.html
deleted file mode 100644
index e3031f56a..000000000
--- a/tests/auto/widgets/loadsignals/resources/page2.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
- <head>
- <title>page2</title>
- </head>
- <style>
- .fardown {
- position: absolute;
- top: 2500px;
- }
- </style>
- <body>
- <div class="fardown" id="anchor">page2 anchor</div>
- </body>
-</html>
diff --git a/tests/auto/widgets/loadsignals/resources/page3.html b/tests/auto/widgets/loadsignals/resources/page3.html
deleted file mode 100644
index d38ca31f0..000000000
--- a/tests/auto/widgets/loadsignals/resources/page3.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
- <head>
- <title>page3</title>
- </head>
- <script>
- setTimeout(function(){
- document.getElementById('anchorLink').click();
- },500);
- </script>
- <style>
- .fardown {
- position: absolute;
- top: 2500px;
- }
- </style>
- <body>
- <div><a id="anchorLink" href="#anchor">page3</a></div>
- <div class="fardown" id="anchor">page3 anchor</div>
- </body>
-</html>
diff --git a/tests/auto/widgets/loadsignals/resources/page4.html b/tests/auto/widgets/loadsignals/resources/page4.html
deleted file mode 100644
index 61976b4fb..000000000
--- a/tests/auto/widgets/loadsignals/resources/page4.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
- <head>
- <title>page4</title>
- </head>
- <body onload="document.getElementById('downloadLink').focus();">
- <a id="downloadLink" href="downloadable.tar.gz">download</a>
- </body>
-</html>
diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
index 20e5fbf0d..6140b3766 100644
--- a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
+++ b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
@@ -1,97 +1,128 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QtTest>
-#include "../util.h"
+#include "httpserver.h"
+#include <util.h>
#include "qdebug.h"
+#include "qwebengineloadinginfo.h"
#include "qwebenginepage.h"
#include "qwebengineprofile.h"
#include "qwebenginesettings.h"
#include "qwebengineview.h"
+enum {
+ LoadStarted = QWebEngineLoadingInfo::LoadStartedStatus,
+ LoadStopped = QWebEngineLoadingInfo::LoadStoppedStatus,
+ LoadSucceeded = QWebEngineLoadingInfo::LoadSucceededStatus,
+ LoadFailed = QWebEngineLoadingInfo::LoadFailedStatus,
+};
+static const QList<int> SignalsOrderOnce({ LoadStarted, LoadSucceeded});
+static const QList<int> SignalsOrderTwice({ LoadStarted, LoadSucceeded, LoadStarted, LoadSucceeded });
+static const QList<int> SignalsOrderOnceFailure({ LoadStarted, LoadFailed });
+static const QList<int> SignalsOrderTwiceWithFailure({ LoadStarted, LoadSucceeded, LoadStarted, LoadFailed });
+
+class TestPage : public QWebEnginePage
+{
+public:
+ QSet<QUrl> blacklist;
+ int navigationRequestCount = 0;
+ QList<int> signalsOrder;
+ QList<int> loadProgress;
+ QList<QWebEngineLoadingInfo> loadingInfos;
+
+ explicit TestPage(QObject *parent = nullptr) : TestPage(nullptr, parent) { }
+ TestPage(QWebEngineProfile *profile, QObject *parent = nullptr) : QWebEnginePage(profile, parent) {
+ connect(this, &QWebEnginePage::loadStarted, [this] () { signalsOrder.append(LoadStarted); });
+ connect(this, &QWebEnginePage::loadProgress, [this] (int p) { loadProgress.append(p); });
+ connect(this, &QWebEnginePage::loadFinished, [this] (bool r) { signalsOrder.append(r ? LoadSucceeded : LoadFailed); });
+ connect(this, &QWebEnginePage::loadingChanged, [this] (const QWebEngineLoadingInfo &i) { loadingInfos.append(i); });
+ }
+ ~TestPage() { Q_ASSERT(signalsOrder.size() == loadingInfos.size()); }
+
+ void reset()
+ {
+ blacklist.clear();
+ navigationRequestCount = 0;
+ signalsOrder.clear();
+ loadProgress.clear();
+ loadingInfos.clear();
+ }
+
+protected:
+ bool acceptNavigationRequest(const QUrl &url, NavigationType, bool) override
+ {
+ ++navigationRequestCount;
+ return !blacklist.contains(url);
+ }
+};
+
class tst_LoadSignals : public QObject
{
Q_OBJECT
-public:
- tst_LoadSignals();
- virtual ~tst_LoadSignals();
-
public Q_SLOTS:
void initTestCase();
void init();
- void cleanup();
private Q_SLOTS:
void monotonicity();
void loadStartedAndFinishedCount_data();
void loadStartedAndFinishedCount();
- void secondLoadForError_WhenErrorPageEnabled_data();
- void secondLoadForError_WhenErrorPageEnabled();
+ void loadStartedAndFinishedCountClick_data();
+ void loadStartedAndFinishedCountClick();
+ void rejectNavigationRequest_data();
+ void rejectNavigationRequest();
void loadAfterInPageNavigation_qtbug66869();
- void fileDownloadDoesNotTriggerLoadSignals_qtbug66661();
+ void fileDownload();
+ void numberOfStartedAndFinishedSignalsIsSame_data();
+ void numberOfStartedAndFinishedSignalsIsSame();
+ void loadFinishedAfterNotFoundError_data();
+ void loadFinishedAfterNotFoundError();
+ void errorPageTriggered_data();
+ void errorPageTriggered();
private:
- QWebEngineView* view;
- QScopedPointer<QSignalSpy> loadStartedSpy;
- QScopedPointer<QSignalSpy> loadProgressSpy;
- QScopedPointer<QSignalSpy> loadFinishedSpy;
+ void clickLink(QPoint linkPos);
+
+ QWebEngineProfile profile;
+ TestPage page{&profile};
+ QWebEngineView view;
+ QSignalSpy loadStartedSpy{&page, &QWebEnginePage::loadStarted};
+ QSignalSpy loadFinishedSpy{&page, &QWebEnginePage::loadFinished};
+ void resetSpies() {
+ loadStartedSpy.clear();
+ loadFinishedSpy.clear();
+ }
};
-tst_LoadSignals::tst_LoadSignals()
-{
-}
-
-tst_LoadSignals::~tst_LoadSignals()
-{
-}
-
void tst_LoadSignals::initTestCase()
{
+ view.setPage(&page);
+ view.resize(640, 480);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
}
void tst_LoadSignals::init()
{
- view = new QWebEngineView();
- view->resize(1024,768);
- view->show();
- loadStartedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadStarted));
- loadProgressSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadProgress));
- loadFinishedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadFinished));
+ // Reset content
+ if (!view.url().isEmpty()) {
+ loadFinishedSpy.clear();
+ view.load(QUrl("about:blank"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ }
+ resetSpies();
+ page.reset();
}
-void tst_LoadSignals::cleanup()
+void tst_LoadSignals::clickLink(QPoint linkPos)
{
- loadFinishedSpy.reset();
- loadProgressSpy.reset();
- loadStartedSpy.reset();
- delete view;
+ // Simulate left-clicking on link.
+ QTRY_VERIFY(view.focusProxy());
+ QWidget *renderWidget = view.focusProxy();
+ QTest::mouseClick(renderWidget, Qt::LeftButton, {}, linkPos);
}
/**
@@ -100,94 +131,168 @@ void tst_LoadSignals::cleanup()
void tst_LoadSignals::loadStartedAndFinishedCount_data()
{
QTest::addColumn<QUrl>("url");
- QTest::addColumn<int>("expectedLoadCount");
- QTest::newRow("Normal") << QUrl("qrc:///resources/page1.html") << 1;
- QTest::newRow("WithAnchor") << QUrl("qrc:///resources/page2.html#anchor") << 1;
-
- // In this case, we get an unexpected additional loadStarted, but no corresponding
- // loadFinished, so expectedLoadCount=2 would also not work. See also QTBUG-65223
- QTest::newRow("WithAnchorClickedFromJS") << QUrl("qrc:///resources/page3.html") << 1;
+ QTest::addColumn<QList<int>>("expectedSignals");
+ QTest::newRow("Simple") << QUrl("qrc:///resources/page1.html") << SignalsOrderOnce;
+ QTest::newRow("SimpleWithAnchor") << QUrl("qrc:///resources/page2.html#anchor") << SignalsOrderOnce;
+ QTest::newRow("SamePageImmediate") << QUrl("qrc:///resources/page5.html") << SignalsOrderOnce;
+ QTest::newRow("SamePageDeferred") << QUrl("qrc:///resources/page3.html") << SignalsOrderOnce;
+ QTest::newRow("OtherPageImmediate") << QUrl("qrc:///resources/page6.html") << SignalsOrderOnce;
+ QTest::newRow("OtherPageDeferred") << QUrl("qrc:///resources/page7.html") << SignalsOrderTwice;
+ QTest::newRow("SamePageImmediateJS") << QUrl("qrc:///resources/page8.html") << SignalsOrderOnce;
}
void tst_LoadSignals::loadStartedAndFinishedCount()
{
QFETCH(QUrl, url);
- QFETCH(int, expectedLoadCount);
+ QFETCH(QList<int>, expectedSignals);
- view->load(url);
- QTRY_COMPARE(loadFinishedSpy->size(), expectedLoadCount);
- bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(loadSucceeded);
+ view.load(url);
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy->size() != expectedLoadCount)
- || (loadFinishedSpy->size() != expectedLoadCount), 10000, 100);
+ int expectedLoadCount = expectedSignals.size() / 2;
+ QTRY_COMPARE(loadStartedSpy.size(), expectedLoadCount);
+ QTRY_COMPARE(loadFinishedSpy.size(), expectedLoadCount);
- // No further loadStarted should have occurred within this time
- QCOMPARE(loadStartedSpy->size(), expectedLoadCount);
- QCOMPARE(loadFinishedSpy->size(), expectedLoadCount);
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != expectedLoadCount || loadFinishedSpy.size() != expectedLoadCount, 1000, 100);
+
+ // No further signals should have occurred within this time and expected number of signals is preserved
+ QCOMPARE(loadStartedSpy.size(), expectedLoadCount);
+ QCOMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.signalsOrder, expectedSignals);
+ QCOMPARE(page.signalsOrder.size(), page.loadingInfos.size());
+ for (int i = 0; i < page.signalsOrder.size(); ++i)
+ QCOMPARE(page.signalsOrder[i], page.loadingInfos[i].status());
}
/**
- * Test monotonicity of loadProgress signals
- */
-void tst_LoadSignals::monotonicity()
+ * Load a URL, then simulate a click to load a different URL.
+ */
+void tst_LoadSignals::loadStartedAndFinishedCountClick_data()
{
- view->load(QUrl("qrc:///resources/page1.html"));
- QTRY_COMPARE(loadFinishedSpy->size(), 1);
- bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(loadSucceeded);
-
- // first loadProgress should have 0% progress
- QCOMPARE(loadProgressSpy->first()[0].toInt(), 0);
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<int>("numberOfSignals");
+ QTest::newRow("SamePage") << QUrl("qrc:///resources/page2.html") << 0; // in-page navigation to anchor shouldn't emit anything
+ QTest::newRow("OtherPage") << QUrl("qrc:///resources/page1.html") << 1;
+}
- // every loadProgress should have at least as much progress as the one before
- int progress = 0;
- for (auto item : *loadProgressSpy) {
- QVERIFY(item[0].toInt() >= progress);
- progress = item[0].toInt();
+void tst_LoadSignals::loadStartedAndFinishedCountClick()
+{
+ QFETCH(QUrl, url);
+ QFETCH(int, numberOfSignals);
+
+ view.load(url);
+ QTRY_COMPARE(loadStartedSpy.size(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
+ resetSpies();
+
+ clickLink(QPoint(10, 10));
+ if (numberOfSignals > 0) {
+ QTRY_COMPARE(loadStartedSpy.size(), numberOfSignals);
+ QTRY_COMPARE(loadFinishedSpy.size(), numberOfSignals);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
}
- // last loadProgress should have 100% progress
- QCOMPARE(loadProgressSpy->last()[0].toInt(), 100);
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != numberOfSignals || loadFinishedSpy.size() != numberOfSignals, 1000, 100);
+
+ // No further loadStarted should have occurred within this time
+ QCOMPARE(loadStartedSpy.size(), numberOfSignals);
+ QCOMPARE(loadFinishedSpy.size(), numberOfSignals);
+ QCOMPARE(page.signalsOrder, numberOfSignals > 0 ? SignalsOrderTwice : SignalsOrderOnce);
+}
+
+void tst_LoadSignals::rejectNavigationRequest_data()
+{
+ QTest::addColumn<QUrl>("initialUrl");
+ QTest::addColumn<QUrl>("rejectedUrl");
+ QTest::addColumn<int>("expectedNavigations");
+ QTest::addColumn<QList<int>>("expectedSignals");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<QWebEngineLoadingInfo::ErrorDomain>("errorDomain");
+ QTest::newRow("Simple")
+ << QUrl("qrc:///resources/page1.html")
+ << QUrl("qrc:///resources/page1.html")
+ << 1 << SignalsOrderOnceFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
+ QTest::newRow("SamePageImmediate")
+ << QUrl("qrc:///resources/page5.html")
+ << QUrl("qrc:///resources/page5.html#anchor")
+ << 1 << SignalsOrderOnce << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("SamePageDeferred")
+ << QUrl("qrc:///resources/page3.html")
+ << QUrl("qrc:///resources/page3.html#anchor")
+ << 1 << SignalsOrderOnce << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("OtherPageImmediate")
+ << QUrl("qrc:///resources/page6.html")
+ << QUrl("qrc:///resources/page2.html#anchor")
+ << 2 << SignalsOrderOnceFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
+ QTest::newRow("OtherPageDeferred")
+ << QUrl("qrc:///resources/page7.html")
+ << QUrl("qrc:///resources/page2.html#anchor")
+ << 2 << SignalsOrderTwiceWithFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
}
/**
- * Test that we get a second loadStarted and loadFinished signal
- * for error-pages (unless error-pages are disabled)
- */
-void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled_data()
+ * Returning false from acceptNavigationRequest means that the load
+ * fails, not that the load never starts.
+ *
+ * See QTBUG-75185.
+ */
+void tst_LoadSignals::rejectNavigationRequest()
{
- QTest::addColumn<bool>("enabled");
- // in this case, we get no second loadStarted and loadFinished, although we had
- // agreed on making the navigation to an error page an individual load
- QTest::newRow("ErrorPageEnabled") << true;
- QTest::newRow("ErrorPageDisabled") << false;
+ QFETCH(QUrl, initialUrl);
+ QFETCH(QUrl, rejectedUrl);
+ QFETCH(int, expectedNavigations);
+ QFETCH(QList<int>, expectedSignals);
+ QFETCH(int, errorCode);
+ QFETCH(QWebEngineLoadingInfo::ErrorDomain, errorDomain);
+
+ page.blacklist.insert(rejectedUrl);
+ page.load(initialUrl);
+ QTRY_COMPARE(page.navigationRequestCount, expectedNavigations);
+ int expectedLoadCount = expectedSignals.size() / 2;
+ QTRY_COMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.signalsOrder, expectedSignals);
+
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != expectedLoadCount || loadFinishedSpy.size() != expectedLoadCount, 1000, 100);
+
+ // No further loadStarted should have occurred within this time
+ QCOMPARE(loadStartedSpy.size(), expectedLoadCount);
+ QCOMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.loadingInfos.last().errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos.last().errorDomain(), errorDomain);
}
-void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled()
+/**
+ * Test monotonicity of loadProgress signals
+ */
+void tst_LoadSignals::monotonicity()
{
- QFETCH(bool, enabled);
- view->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, enabled);
- int expectedLoadCount = (enabled ? 2 : 1);
-
- // RFC 2606 guarantees that this will never become a valid domain
- view->load(QUrl("http://nonexistent.invalid"));
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy->size(), expectedLoadCount, 10000);
- bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(!loadSucceeded);
- if (enabled) {
- bool errorPageLoadSucceeded = (*loadFinishedSpy)[1][0].toBool();
- QVERIFY(errorPageLoadSucceeded);
- }
+ HttpServer server;
+ server.setResourceDirs({ server.sharedDataDir() });
+ connect(&server, &HttpServer::newRequest, [] (HttpReqRep *) {
+ QTest::qWait(250); // just add delay to trigger some progress for every sub resource
+ });
+ QVERIFY(server.start());
+
+ view.load(server.url("/loadprogress/main.html"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 10000);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
+
+ QVERIFY(page.loadProgress.size() >= 3);
+ // first loadProgress should have 0% progress
+ QCOMPARE(page.loadProgress.first(), 0);
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy->size() != expectedLoadCount)
- || (loadFinishedSpy->size() != expectedLoadCount), 10000, 100);
+ // every loadProgress should have more progress than the one before
+ int progress = -1;
+ for (int p : page.loadProgress) {
+ QVERIFY(progress < p);
+ progress = p;
+ }
- // No further loadStarted should have occurred within this time
- QCOMPARE(loadStartedSpy->size(), expectedLoadCount);
- QCOMPARE(loadFinishedSpy->size(), expectedLoadCount);
+ // last loadProgress should have 100% progress
+ QCOMPARE(page.loadProgress.last(), 100);
}
/**
@@ -196,70 +301,236 @@ void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled()
*/
void tst_LoadSignals::loadAfterInPageNavigation_qtbug66869()
{
- view->load(QUrl("qrc:///resources/page3.html"));
- QTRY_COMPARE(loadFinishedSpy->size(), 1);
- bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(loadSucceeded);
+ view.load(QUrl("qrc:///resources/page3.html"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
// page3 does an in-page navigation after 500ms
- QTest::qWait(2000);
- loadFinishedSpy->clear();
- loadProgressSpy->clear();
- loadStartedSpy->clear();
+ QTRY_COMPARE(view.url(), QUrl("qrc:///resources/page3.html#anchor"));
// second load
- view->load(QUrl("qrc:///resources/page1.html"));
- QTRY_COMPARE(loadFinishedSpy->size(), 1);
- loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(loadSucceeded);
+ view.load(QUrl("qrc:///resources/page1.html"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
// loadStarted and loadFinished should have been signalled
- QCOMPARE(loadStartedSpy->size(), 1);
-
- // reminder that we still need to solve the core issue
- QFAIL("https://codereview.qt-project.org/#/c/222112/ only hides the symptom, the core issue still needs to be solved");
+ QCOMPARE(loadStartedSpy.size(), 2);
}
-/**
- * Test that file-downloads don't trigger loadStarted or loadFinished signals.
- * See QTBUG-66661
- */
-void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
+void tst_LoadSignals::fileDownload()
{
- view->load(QUrl("qrc:///resources/page4.html"));
- QTRY_COMPARE(loadFinishedSpy->size(), 1);
- bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
- QVERIFY(loadSucceeded);
+ view.load(QUrl("qrc:///resources/page4.html"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
// allow the download
QTemporaryDir tempDir;
- QWebEngineDownloadItem::DownloadState downloadState = QWebEngineDownloadItem::DownloadRequested;
- connect(view->page()->profile(), &QWebEngineProfile::downloadRequested,
- [&downloadState, &tempDir](QWebEngineDownloadItem* item){
- connect(item, &QWebEngineDownloadItem::stateChanged, [&downloadState](QWebEngineDownloadItem::DownloadState newState){
- downloadState = newState;
- });
- item->setDownloadDirectory(tempDir.filePath(QFileInfo(item->path()).path()));
- item->setDownloadFileName(QFileInfo(item->path()).fileName());
- item->accept();
- });
+ QVERIFY(tempDir.isValid());
+ QWebEngineDownloadRequest::DownloadState downloadState = QWebEngineDownloadRequest::DownloadRequested;
+ ScopedConnection sc1 =
+ connect(&profile, &QWebEngineProfile::downloadRequested,
+ [&downloadState, &tempDir](QWebEngineDownloadRequest *item) {
+ connect(item, &QWebEngineDownloadRequest::stateChanged,
+ [&downloadState](QWebEngineDownloadRequest::DownloadState newState) {
+ downloadState = newState;
+ });
+ item->setDownloadDirectory(tempDir.path());
+ item->accept();
+ });
// trigger the download link that becomes focused on page4
- QTest::qWait(1000);
- 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);
-
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy->size() != 1)
- || (loadFinishedSpy->size() != 1), 10000, 100);
+ 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);
// Download must have occurred
- QTRY_COMPARE(downloadState, QWebEngineDownloadItem::DownloadCompleted);
+ QTRY_COMPARE(downloadState, QWebEngineDownloadRequest::DownloadCompleted);
+ QTRY_COMPARE(loadFinishedSpy.size() + loadStartedSpy.size(), 4);
- // No further loadStarted should have occurred within this time
- QCOMPARE(loadStartedSpy->size(), 1);
- QCOMPARE(loadFinishedSpy->size(), 1);
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != 2 || loadFinishedSpy.size() != 2, 1000, 100);
+
+ QCOMPARE(page.signalsOrder, SignalsOrderTwiceWithFailure);
+ QCOMPARE(page.loadingInfos[3].errorCode(), -3);
+ QCOMPARE(page.loadingInfos[3].errorDomain(), QWebEngineLoadingInfo::InternalErrorDomain);
+}
+
+void tst_LoadSignals::numberOfStartedAndFinishedSignalsIsSame_data()
+{
+ QTest::addColumn<bool>("imageFromServer");
+ QTest::addColumn<QString>("imageResourceUrl");
+ // triggers these calls in delegate internally:
+ // just two ordered triples DidStartNavigation/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("no_image_resource") << false << "";
+ // out of order: DidStartNavigation/DidFinishNavigation/DidStartNavigation/DidFailLoad/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("with_invalid_image") << false << "https://non.existent.locahost/image.png";
+ // out of order: DidStartNavigation/DidFinishNavigation/DidStartNavigation/DidFinishLoad/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("with_server_image") << true << "";
+}
+
+void tst_LoadSignals::numberOfStartedAndFinishedSignalsIsSame()
+{
+ QFETCH(bool, imageFromServer);
+ QFETCH(QString, imageResourceUrl);
+
+ HttpServer server;
+ server.setResourceDirs({ server.sharedDataDir() });
+ QVERIFY(server.start());
+
+ QUrl serverImage = server.url("/hedgehog.png");
+ QString imageUrl(!imageFromServer && imageResourceUrl.isEmpty()
+ ? "" : (imageFromServer ? serverImage.toEncoded() : imageResourceUrl));
+
+ auto html = "<html><head><link rel='icon' href='data:,'></head><body>"
+ "%1" "<form method='GET' name='hiddenform' action='qrc:///resources/page1.html' />"
+ "<script language='javascript'>document.forms[0].submit();</script>"
+ "</body></html>";
+ view.page()->setHtml(QString(html).arg(imageUrl.isEmpty() ? "" : "<img src='" + imageUrl + "'>"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+
+ resetSpies();
+ QTRY_LOOP_IMPL(loadStartedSpy.size() || loadFinishedSpy.size(), 1000, 100);
+ QCOMPARE(page.signalsOrder, SignalsOrderOnce);
+ QCOMPARE(page.loadingInfos[1].errorCode(), 200);
+ QCOMPARE(page.loadingInfos[1].errorDomain(), QWebEngineLoadingInfo::HttpStatusCodeDomain);
+}
+
+void tst_LoadSignals::loadFinishedAfterNotFoundError_data()
+{
+ QTest::addColumn<bool>("rfcInvalid");
+ QTest::addColumn<bool>("withServer");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<int>("errorDomain");
+ QTest::addRow("rfc_invalid") << true << false << -105 << int(QWebEngineLoadingInfo::ConnectionErrorDomain);
+ QTest::addRow("non_existent") << false << false << -105 << int(QWebEngineLoadingInfo::ConnectionErrorDomain);
+ QTest::addRow("server_404") << false << true << 404 << int(QWebEngineLoadingInfo::HttpStatusCodeDomain);
}
+void tst_LoadSignals::loadFinishedAfterNotFoundError()
+{
+ QFETCH(bool, rfcInvalid);
+ QFETCH(bool, withServer);
+ QFETCH(int, errorCode);
+ QFETCH(int, errorDomain);
+
+ QScopedPointer<HttpServer> server;
+ if (withServer) {
+ server.reset(new HttpServer);
+ QVERIFY(server->start());
+ }
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ auto url = server
+ ? server->url("/not-found-page.html")
+ : QUrl(rfcInvalid ? "http://some.invalid" : "http://non.existent/url");
+ view.load(url);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 20000);
+ QVERIFY(!loadFinishedSpy.at(0).at(0).toBool());
+ QCOMPARE(toPlainTextSync(view.page()), QString());
+ QCOMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadStartedSpy.size(), 1);
+ QVERIFY(std::is_sorted(page.loadProgress.begin(), page.loadProgress.end()));
+ page.loadProgress.clear();
+
+ { auto &&loadStart = page.loadingInfos[0], &&loadFinish = page.loadingInfos[1];
+ QCOMPARE(loadStart.status(), QWebEngineLoadingInfo::LoadStartedStatus);
+ QCOMPARE(loadStart.isErrorPage(), false);
+ QCOMPARE(loadStart.errorCode(), 0);
+ QCOMPARE(loadStart.errorDomain(), QWebEngineLoadingInfo::NoErrorDomain);
+ QCOMPARE(loadStart.errorString(), QString());
+ QCOMPARE(loadFinish.status(), QWebEngineLoadingInfo::LoadFailedStatus);
+ QCOMPARE(loadFinish.isErrorPage(), false);
+ QCOMPARE(loadFinish.errorCode(), errorCode);
+ QCOMPARE(loadFinish.errorDomain(), errorDomain);
+ QVERIFY(!loadFinish.errorString().isEmpty());
+ }
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
+ url = server
+ ? server->url("/another-missing-one.html")
+ : QUrl(rfcInvalid ? "http://some.other.invalid" : "http://another.non.existent/url");
+ view.load(url);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 20000);
+ QVERIFY(!loadFinishedSpy.at(1).at(0).toBool());
+ QCOMPARE(loadStartedSpy.size(), 2);
+
+ QEXPECT_FAIL("", "No more loads (like separate load for error pages) are expected", Continue);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 3, 1000);
+ QCOMPARE(loadStartedSpy.size(), 2);
+ QVERIFY(std::is_sorted(page.loadProgress.begin(), page.loadProgress.end()));
+
+ { auto &&loadStart = page.loadingInfos[2], &&loadFinish = page.loadingInfos[3];
+ QCOMPARE(loadStart.status(), QWebEngineLoadingInfo::LoadStartedStatus);
+ QCOMPARE(loadStart.isErrorPage(), false);
+ QCOMPARE(loadStart.errorCode(), 0);
+ QCOMPARE(loadStart.errorDomain(), QWebEngineLoadingInfo::NoErrorDomain);
+ QCOMPARE(loadStart.errorString(), QString());
+ QCOMPARE(loadFinish.status(), QWebEngineLoadingInfo::LoadFailedStatus);
+ QCOMPARE(loadFinish.isErrorPage(), true);
+ QCOMPARE(loadFinish.errorCode(), errorCode);
+ QCOMPARE(loadFinish.errorDomain(), errorDomain);
+ QVERIFY(!loadFinish.errorString().isEmpty());
+ }
+}
+
+void tst_LoadSignals::errorPageTriggered_data()
+{
+ QTest::addColumn<QString>("urlPath");
+ QTest::addColumn<bool>("loadSucceed");
+ QTest::addColumn<bool>("triggersErrorPage");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<QWebEngineLoadingInfo::ErrorDomain>("errorDomain");
+ QTest::newRow("/content/200") << QStringLiteral("/content/200") << true << false << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/empty/200") << QStringLiteral("/content/200") << true << false << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/content/404") << QStringLiteral("/content/404") << false << false << 404 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/empty/404") << QStringLiteral("/empty/404") << false << true << 404 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+}
+
+void tst_LoadSignals::errorPageTriggered()
+{
+ HttpServer server;
+ connect(&server, &HttpServer::newRequest, [] (HttpReqRep *rr) {
+ QList<QByteArray> parts = rr->requestPath().split('/');
+ if (parts.size() != 3) {
+ // For example, /favicon.ico
+ rr->sendResponse(404);
+ return;
+ }
+ bool isDocumentEmpty = (parts[1] == "empty");
+ int httpStatusCode = parts[2].toInt();
+
+ rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("text/html"));
+ if (!isDocumentEmpty) {
+ rr->setResponseBody(QByteArrayLiteral("<html></html>"));
+ }
+ rr->sendResponse(httpStatusCode);
+ });
+ QVERIFY(server.start());
+
+ QFETCH(QString, urlPath);
+ QFETCH(bool, loadSucceed);
+ QFETCH(bool, triggersErrorPage);
+ QFETCH(int, errorCode);
+ QFETCH(QWebEngineLoadingInfo::ErrorDomain, errorDomain);
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
+ view.load(server.url(urlPath));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadFinishedSpy[0][0].toBool(), loadSucceed);
+ if (triggersErrorPage)
+ QVERIFY(toPlainTextSync(view.page()).contains("HTTP ERROR 404"));
+ else
+ QVERIFY(toPlainTextSync(view.page()).isEmpty());
+ QCOMPARE(page.loadingInfos[1].errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos[1].errorDomain(), errorDomain);
+ loadFinishedSpy.clear();
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ view.load(server.url(urlPath));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadFinishedSpy[0][0].toBool(), loadSucceed);
+ QVERIFY(toPlainTextSync(view.page()).isEmpty());
+ QCOMPARE(page.loadingInfos[3].errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos[3].errorDomain(), errorDomain);
+ loadFinishedSpy.clear();
+}
QTEST_MAIN(tst_LoadSignals)
#include "tst_loadsignals.moc"
diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.qrc b/tests/auto/widgets/loadsignals/tst_loadsignals.qrc
deleted file mode 100644
index 316deecb8..000000000
--- a/tests/auto/widgets/loadsignals/tst_loadsignals.qrc
+++ /dev/null
@@ -1,9 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>resources/page1.html</file>
- <file>resources/page2.html</file>
- <file>resources/page3.html</file>
- <file>resources/page4.html</file>
- <file>resources/downloadable.tar.gz</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/widgets/offscreen/CMakeLists.txt b/tests/auto/widgets/offscreen/CMakeLists.txt
new file mode 100644
index 000000000..756e53c43
--- /dev/null
+++ b/tests/auto/widgets/offscreen/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_offscreen
+ SOURCES
+ tst_offscreen.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+)
+
+set(tst_offscreen_resource_files
+ "test.html"
+)
+
+set_tests_properties(tst_offscreen PROPERTIES
+ ENVIRONMENT QT_QPA_PLATFORM=offscreen
+)
+
+qt_internal_add_resource(tst_offscreen "tst_offscreen"
+ PREFIX
+ "/"
+ FILES
+ ${tst_offscreen_resource_files}
+)
+
diff --git a/tests/auto/widgets/offscreen/offscreen.pro b/tests/auto/widgets/offscreen/offscreen.pro
deleted file mode 100644
index b8e5632f9..000000000
--- a/tests/auto/widgets/offscreen/offscreen.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-include(../tests.pri)
-QT += webengine
-qpa.name = QT_QPA_PLATFORM
-qpa.value = offscreen
-QT_TOOL_ENV += qpa
-
diff --git a/tests/auto/widgets/offscreen/tst_offscreen.cpp b/tests/auto/widgets/offscreen/tst_offscreen.cpp
index 7573b0537..553dc653b 100644
--- a/tests/auto/widgets/offscreen/tst_offscreen.cpp
+++ b/tests/auto/widgets/offscreen/tst_offscreen.cpp
@@ -1,32 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include "qtwebengineglobal.h"
#include <QTest>
#include <QSignalSpy>
#include <QWebEngineProfile>
@@ -52,7 +26,7 @@ void tst_OffScreen::offscreen()
page.load(QUrl("qrc:/test.html"));
view.show();
QTRY_COMPARE(view.isVisible(), true);
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count() > 0, true, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size() > 0, true, 20000);
QCOMPARE(loadFinishedSpy.takeFirst().at(0).toBool(), true);
}
diff --git a/tests/auto/widgets/offscreen/tst_offscreen.qrc b/tests/auto/widgets/offscreen/tst_offscreen.qrc
deleted file mode 100644
index 8a998fe85..000000000
--- a/tests/auto/widgets/offscreen/tst_offscreen.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>test.html</file>
-</qresource>
-</RCC>
-
diff --git a/tests/auto/widgets/origins/origins.pro b/tests/auto/widgets/origins/origins.pro
deleted file mode 100644
index 7498354de..000000000
--- a/tests/auto/widgets/origins/origins.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-include(../tests.pri)
-CONFIG += c++14
-qtConfig(webengine-webchannel):qtHaveModule(websockets) {
- QT += websockets
- DEFINES += WEBSOCKETS
-}
-
diff --git a/tests/auto/widgets/origins/resources/createObjectURL.html b/tests/auto/widgets/origins/resources/createObjectURL.html
deleted file mode 100644
index 133f636bb..000000000
--- a/tests/auto/widgets/origins/resources/createObjectURL.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>createObjectURL</title>
- <script>
- const blob = new Blob(['foo']);
- const result = URL.createObjectURL(blob);
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/dedicatedWorker.html b/tests/auto/widgets/origins/resources/dedicatedWorker.html
deleted file mode 100644
index cb4f14e73..000000000
--- a/tests/auto/widgets/origins/resources/dedicatedWorker.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>dedicatedWorker</title>
- <script>
- var done = false;
- var result;
- var error;
- try {
- let worker = new Worker("dedicatedWorker.js");
- worker.onmessage = (e) => { done = true; result = e.data; };
- worker.postMessage(41);
- } catch (e) {
- done = true; error = e.message;
- }
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/dedicatedWorker.js b/tests/auto/widgets/origins/resources/dedicatedWorker.js
deleted file mode 100644
index 2631939d7..000000000
--- a/tests/auto/widgets/origins/resources/dedicatedWorker.js
+++ /dev/null
@@ -1 +0,0 @@
-onmessage = (e) => { postMessage(e.data + 1); };
diff --git a/tests/auto/widgets/origins/resources/mixedSchemes.html b/tests/auto/widgets/origins/resources/mixedSchemes.html
deleted file mode 100644
index c73e9ecdc..000000000
--- a/tests/auto/widgets/origins/resources/mixedSchemes.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Mixed</title>
- <script>
- var result;
- var canary;
-
- function setIFrameUrl(url) {
- result = undefined;
- canary = undefined;
- document.getElementById("iframe").setAttribute("src", url);
- // Early fire is OK unless the test is expecting cannotLoad.
- // If timeout is too short then a false positive is possible.
- setTimeout(() => { result = result || "cannotLoad"; }, 500);
- }
-
- addEventListener("load", function() {
- document.getElementById("iframe").addEventListener("load", function() {
- if (canary && window[0].canary)
- result = "canLoadAndAccess";
- else
- result = "canLoadButNotAccess";
- });
- });
- </script>
- </head>
- <body>
- <iframe id="iframe"></iframe>
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html b/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html
deleted file mode 100644
index ad7cbeeb7..000000000
--- a/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta http-equiv="Content-Security-Policy" content="frame-src 'none'">
- <title>Mixed</title>
- <script>
- var result;
- var canary;
-
- function setIFrameUrl(url) {
- result = undefined;
- canary = undefined;
- document.getElementById("iframe").setAttribute("src", url);
- // Early fire is OK unless the test is expecting cannotLoad.
- // If timeout is too short then a false positive is possible.
- setTimeout(() => { result = result || "cannotLoad"; }, 500);
- }
-
- addEventListener("load", function() {
- document.getElementById("iframe").addEventListener("load", function() {
- if (canary && window[0].canary)
- result = "canLoadAndAccess";
- else
- result = "canLoadButNotAccess";
- });
- });
- </script>
- </head>
- <body>
- <iframe id="iframe"></iframe>
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/mixedSchemes_frame.html b/tests/auto/widgets/origins/resources/mixedSchemes_frame.html
deleted file mode 100644
index 00c20ba37..000000000
--- a/tests/auto/widgets/origins/resources/mixedSchemes_frame.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Mixed - Frame</title>
- <script>
- var canary = true;
- parent.canary = true;
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/mixedXHR.html b/tests/auto/widgets/origins/resources/mixedXHR.html
deleted file mode 100644
index 3dfd90006..000000000
--- a/tests/auto/widgets/origins/resources/mixedXHR.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Mixed</title>
- <script>
- var result;
- function sendXHR(url) {
- result = undefined;
- let req = new XMLHttpRequest();
- req.addEventListener("load", () => { result = req.responseText });
- req.addEventListener("error", () => { result = "error"; });
- req.open("GET", url);
- req.send();
- }
- </script>
- </head>
- <body>
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/mixedXHR.txt b/tests/auto/widgets/origins/resources/mixedXHR.txt
deleted file mode 100644
index b5754e203..000000000
--- a/tests/auto/widgets/origins/resources/mixedXHR.txt
+++ /dev/null
@@ -1 +0,0 @@
-ok \ No newline at end of file
diff --git a/tests/auto/widgets/origins/resources/redirect.css b/tests/auto/widgets/origins/resources/redirect.css
deleted file mode 100644
index 41d7560cc..000000000
--- a/tests/auto/widgets/origins/resources/redirect.css
+++ /dev/null
@@ -1,8 +0,0 @@
-@font-face {
- font-family: 'MyWebFont';
- src: url('redirect1:/resources/Akronim-Regular.woff2') format('woff2');
-}
-
-body {
- font-family: 'MyWebFont', Fallback, sans-serif;
-}
diff --git a/tests/auto/widgets/origins/resources/redirect.html b/tests/auto/widgets/origins/resources/redirect.html
deleted file mode 100644
index 04948e14b..000000000
--- a/tests/auto/widgets/origins/resources/redirect.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>redirect</title>
- <link rel="stylesheet" href="redirect1:/resources/redirect.css">
- </head>
- <body>
- Text
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/serviceWorker.html b/tests/auto/widgets/origins/resources/serviceWorker.html
deleted file mode 100644
index 27890c98f..000000000
--- a/tests/auto/widgets/origins/resources/serviceWorker.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>serviceWorker</title>
- <script>
- var done = false;
- var error;
- try {
- navigator.serviceWorker.register("serviceWorker.js")
- .then((r) => { done = true; })
- .catch((e) => { done = true; error = e.message; });
- } catch (e) {
- done = true; error = e.message;
- }
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/serviceWorker.js b/tests/auto/widgets/origins/resources/serviceWorker.js
deleted file mode 100644
index 40a8c178f..000000000
--- a/tests/auto/widgets/origins/resources/serviceWorker.js
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/tests/auto/widgets/origins/resources/sharedWorker.html b/tests/auto/widgets/origins/resources/sharedWorker.html
deleted file mode 100644
index 8b5a0a794..000000000
--- a/tests/auto/widgets/origins/resources/sharedWorker.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>sharedWorker</title>
- <script>
- var done;
- var result;
- var error;
- try {
- let worker = new SharedWorker("sharedWorker.js");
- worker.port.onmessage = (e) => { done = true; result = e.data; };
- worker.port.postMessage(41);
- } catch (e) {
- done = true; error = e.message;
- }
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/sharedWorker.js b/tests/auto/widgets/origins/resources/sharedWorker.js
deleted file mode 100644
index 60ef93a5f..000000000
--- a/tests/auto/widgets/origins/resources/sharedWorker.js
+++ /dev/null
@@ -1,6 +0,0 @@
-onconnect = function(e) {
- let port = e.ports[0];
- port.onmessage = function(e) {
- port.postMessage(e.data + 1);
- };
-};
diff --git a/tests/auto/widgets/origins/resources/subdir/frame2.html b/tests/auto/widgets/origins/resources/subdir/frame2.html
deleted file mode 100644
index 3a2f664ca..000000000
--- a/tests/auto/widgets/origins/resources/subdir/frame2.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Subdir - Frame 2</title>
- <script>
- parent.msg[1] = "world";
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/subdir/index.html b/tests/auto/widgets/origins/resources/subdir/index.html
deleted file mode 100644
index 9c5d5d782..000000000
--- a/tests/auto/widgets/origins/resources/subdir/index.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Subdir</title>
-
- <script>
- var msg = [];
- </script>
-
- <!-- for manual testing -->
- <script>
- window.addEventListener("load", () => {
- for (let i of [0, 1]) {
- let p = document.createElement("p");
- p.appendChild(document.createTextNode(`frame ${i+1} says: ${msg[i]}`));
- document.body.insertBefore(p, null);
- }
- });
- </script>
-
- </head>
- <body>
- <iframe src="../subdir_frame1.html"></iframe>
- <iframe src="frame2.html"></iframe>
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/subdir_frame1.html b/tests/auto/widgets/origins/resources/subdir_frame1.html
deleted file mode 100644
index 63973f2f4..000000000
--- a/tests/auto/widgets/origins/resources/subdir_frame1.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Subdir - Frame 1</title>
- <script>
- parent.msg[0] = "hello";
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/viewSource.html b/tests/auto/widgets/origins/resources/viewSource.html
deleted file mode 100644
index 977074c74..000000000
--- a/tests/auto/widgets/origins/resources/viewSource.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>viewSource</title>
- </head>
- <body>
- <p>viewSource</p>
- </body>
-</html>
diff --git a/tests/auto/widgets/origins/resources/websocket.html b/tests/auto/widgets/origins/resources/websocket.html
deleted file mode 100644
index 31db66571..000000000
--- a/tests/auto/widgets/origins/resources/websocket.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>WebSocket</title>
- <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
- <script>
- var result;
- new QWebChannel(qt.webChannelTransport, channel => {
- const ws = new WebSocket(channel.objects.echoServer.url);
- ws.addEventListener("open", event => {
- ws.send("ok");
- });
- ws.addEventListener("message", event => {
- result = event.data;
- });
- ws.addEventListener("close", event => {
- result = event.code;
- });
- })
- </script>
- </head>
- <body></body>
-</html>
diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp
deleted file mode 100644
index e3927f763..000000000
--- a/tests/auto/widgets/origins/tst_origins.cpp
+++ /dev/null
@@ -1,874 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "../util.h"
-
-#include <QtCore/qfile.h>
-#include <QtTest/QtTest>
-#include <QtWebEngineCore/qwebengineurlrequestjob.h>
-#include <QtWebEngineCore/qwebengineurlscheme.h>
-#include <QtWebEngineCore/qwebengineurlschemehandler.h>
-#include <QtWebEngineWidgets/qwebenginepage.h>
-#include <QtWebEngineWidgets/qwebengineprofile.h>
-#include <QtWebEngineWidgets/qwebenginesettings.h>
-#if defined(WEBSOCKETS)
-#include <QtWebSockets/qwebsocket.h>
-#include <QtWebSockets/qwebsocketserver.h>
-#include <QtWebChannel/qwebchannel.h>
-#endif
-#include <QtWidgets/qaction.h>
-
-#define QSL QStringLiteral
-#define QBAL QByteArrayLiteral
-#define THIS_DIR TESTS_SOURCE_DIR "origins/"
-
-void registerSchemes()
-{
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax"));
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure"));
- scheme.setFlags(QWebEngineUrlScheme::SecureScheme);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure-ServiceWorkersAllowed"));
- scheme.setFlags(QWebEngineUrlScheme::SecureScheme | QWebEngineUrlScheme::ServiceWorkersAllowed);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-Local"));
- scheme.setFlags(QWebEngineUrlScheme::LocalScheme);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-LocalAccessAllowed"));
- scheme.setFlags(QWebEngineUrlScheme::LocalAccessAllowed);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-NoAccessAllowed"));
- scheme.setFlags(QWebEngineUrlScheme::NoAccessAllowed);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-ServiceWorkersAllowed"));
- scheme.setFlags(QWebEngineUrlScheme::ServiceWorkersAllowed);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("PathSyntax-ViewSourceAllowed"));
- scheme.setFlags(QWebEngineUrlScheme::ViewSourceAllowed);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("HostSyntax"));
- scheme.setSyntax(QWebEngineUrlScheme::Syntax::Host);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("HostSyntax-ContentSecurityPolicyIgnored"));
- scheme.setSyntax(QWebEngineUrlScheme::Syntax::Host);
- scheme.setFlags(QWebEngineUrlScheme::ContentSecurityPolicyIgnored);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("HostAndPortSyntax"));
- scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort);
- scheme.setDefaultPort(42);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("HostPortAndUserInformationSyntax"));
- scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostPortAndUserInformation);
- scheme.setDefaultPort(42);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("redirect1"));
- scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("redirect2"));
- scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
- {
- QWebEngineUrlScheme scheme(QBAL("cors"));
- scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
- QWebEngineUrlScheme::registerScheme(scheme);
- }
-
-}
-Q_CONSTRUCTOR_FUNCTION(registerSchemes)
-
-class TstUrlSchemeHandler final : public QWebEngineUrlSchemeHandler {
- Q_OBJECT
-
-public:
- TstUrlSchemeHandler(QWebEngineProfile *profile)
- {
- profile->installUrlSchemeHandler(QBAL("tst"), this);
-
- profile->installUrlSchemeHandler(QBAL("PathSyntax"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure-ServiceWorkersAllowed"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-Local"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-LocalAccessAllowed"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-NoAccessAllowed"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-ServiceWorkersAllowed"), this);
- profile->installUrlSchemeHandler(QBAL("PathSyntax-ViewSourceAllowed"), this);
- profile->installUrlSchemeHandler(QBAL("HostSyntax"), this);
- profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this);
- profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this);
- profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this);
- profile->installUrlSchemeHandler(QBAL("redirect1"), this);
- profile->installUrlSchemeHandler(QBAL("redirect2"), this);
- profile->installUrlSchemeHandler(QBAL("cors"), this);
- }
-
- QVector<QUrl> &requests() { return m_requests; }
-
-private:
- void requestStarted(QWebEngineUrlRequestJob *job) override
- {
- QUrl url = job->requestUrl();
- m_requests << url;
-
- if (url.scheme() == QBAL("redirect1")) {
- url.setScheme(QBAL("redirect2"));
- job->redirect(url);
- return;
- }
-
- QString pathPrefix = QSL(THIS_DIR);
- QString pathSuffix = url.path();
- QFile *file = new QFile(pathPrefix + pathSuffix, job);
- if (!file->open(QIODevice::ReadOnly)) {
- job->fail(QWebEngineUrlRequestJob::RequestFailed);
- return;
- }
- QByteArray mimeType = QBAL("text/html");
- if (pathSuffix.endsWith(QSL(".js")))
- mimeType = QBAL("application/javascript");
- else if (pathSuffix.endsWith(QSL(".css")))
- mimeType = QBAL("text/css");
- job->reply(mimeType, file);
- }
-
- QVector<QUrl> m_requests;
-};
-
-class tst_Origins final : public QObject {
- Q_OBJECT
-
-private Q_SLOTS:
- void initTestCase();
- void cleanupTestCase();
- void init();
- void cleanup();
-
- void jsUrlCanon();
- void jsUrlRelative();
- void jsUrlOrigin();
- void subdirWithAccess();
- void subdirWithoutAccess();
- void mixedSchemes();
- void mixedSchemesWithCsp();
- void mixedXHR();
-#if defined(WEBSOCKETS)
- void webSocket();
-#endif
- void dedicatedWorker();
- void sharedWorker();
- void serviceWorker();
- void viewSource();
- void createObjectURL();
- void redirect();
-
-private:
- bool verifyLoad(const QUrl &url)
- {
- QSignalSpy spy(m_page, &QWebEnginePage::loadFinished);
- m_page->load(url);
- [&spy]() { QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty(), 90000); }();
- return !spy.isEmpty() && spy.front().value(0).toBool();
- }
-
- QVariant eval(const QString &code)
- {
- return evaluateJavaScriptSync(m_page, code);
- }
-
- QWebEngineProfile m_profile;
- QWebEnginePage *m_page = nullptr;
- TstUrlSchemeHandler *m_handler = nullptr;
-};
-
-void tst_Origins::initTestCase()
-{
- QTest::ignoreMessage(
- QtWarningMsg,
- QRegularExpression("Please register the custom scheme 'tst'.*"));
-
- m_handler = new TstUrlSchemeHandler(&m_profile);
-}
-
-void tst_Origins::cleanupTestCase()
-{
- QVERIFY(!m_page);
- delete m_handler;
-}
-
-void tst_Origins::init()
-{
- m_page = new QWebEnginePage(&m_profile, nullptr);
-}
-
-void tst_Origins::cleanup()
-{
- delete m_page;
- m_page = nullptr;
- m_handler->requests().clear();
-}
-
-// Test URL parsing and canonicalization in Blink. The implementation of this
-// part is mostly shared between Blink and Chromium proper.
-void tst_Origins::jsUrlCanon()
-{
- QVERIFY(verifyLoad(QSL("about:blank")));
-
- // Standard schemes are biased towards the authority part.
- QCOMPARE(eval(QSL("new URL(\"http:foo/bar\").href")), QVariant(QSL("http://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"http:/foo/bar\").href")), QVariant(QSL("http://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"http://foo/bar\").href")), QVariant(QSL("http://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"http:///foo/bar\").href")), QVariant(QSL("http://foo/bar")));
-
- // The file scheme is however a (particularly) special case.
-#ifdef Q_OS_WIN
- QCOMPARE(eval(QSL("new URL(\"file:foo/bar\").href")), QVariant(QSL("file://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file:/foo/bar\").href")), QVariant(QSL("file://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file://foo/bar\").href")), QVariant(QSL("file://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file:///foo/bar\").href")), QVariant(QSL("file:///foo/bar")));
-#else
- QCOMPARE(eval(QSL("new URL(\"file:foo/bar\").href")), QVariant(QSL("file:///foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file:/foo/bar\").href")), QVariant(QSL("file:///foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file://foo/bar\").href")), QVariant(QSL("file://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"file:///foo/bar\").href")), QVariant(QSL("file:///foo/bar")));
-#endif
-
- // The qrc scheme is a PathSyntax scheme, having only a path and nothing else.
- QCOMPARE(eval(QSL("new URL(\"qrc:foo/bar\").href")), QVariant(QSL("qrc:foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"qrc:/foo/bar\").href")), QVariant(QSL("qrc:/foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"qrc://foo/bar\").href")), QVariant(QSL("qrc://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"qrc:///foo/bar\").href")), QVariant(QSL("qrc:///foo/bar")));
-
- // Same for unregistered schemes.
- QCOMPARE(eval(QSL("new URL(\"tst:foo/bar\").href")), QVariant(QSL("tst:foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"tst:/foo/bar\").href")), QVariant(QSL("tst:/foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"tst://foo/bar\").href")), QVariant(QSL("tst://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"tst:///foo/bar\").href")), QVariant(QSL("tst:///foo/bar")));
-
- // A HostSyntax scheme is like http without the port & user information.
- QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:42/bar\").href")), QVariant(QSL("hostsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostSyntax:a:b@foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar")));
-
- // A HostAndPortSyntax scheme is like http without the user information.
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo/bar\").href")),
- QVariant(QSL("hostandportsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").href")),
- QVariant(QSL("hostandportsyntax://foo:41/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").href")),
- QVariant(QSL("hostandportsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:a:b@foo/bar\").href")),
- QVariant(QSL("hostandportsyntax://foo/bar")));
-
- // A HostPortAndUserInformationSyntax scheme is exactly like http.
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo/bar\").href")),
- QVariant(QSL("hostportanduserinformationsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").href")),
- QVariant(QSL("hostportanduserinformationsyntax://foo:41/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").href")),
- QVariant(QSL("hostportanduserinformationsyntax://foo/bar")));
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:a:b@foo/bar\").href")),
- QVariant(QSL("hostportanduserinformationsyntax://a:b@foo/bar")));
-}
-
-// Test relative URL resolution.
-void tst_Origins::jsUrlRelative()
-{
- QVERIFY(verifyLoad(QSL("about:blank")));
-
- // Schemes with hosts, like http, work as expected.
- QCOMPARE(eval(QSL("new URL('bar', 'http://foo').href")), QVariant(QSL("http://foo/bar")));
- QCOMPARE(eval(QSL("new URL('baz', 'http://foo/bar').href")), QVariant(QSL("http://foo/baz")));
- QCOMPARE(eval(QSL("new URL('baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/bar/baz")));
- QCOMPARE(eval(QSL("new URL('/baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz")));
- QCOMPARE(eval(QSL("new URL('./baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/bar/baz")));
- QCOMPARE(eval(QSL("new URL('../baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz")));
- QCOMPARE(eval(QSL("new URL('../../baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz")));
- QCOMPARE(eval(QSL("new URL('//baz', 'http://foo/bar/').href")), QVariant(QSL("http://baz/")));
-
- // In the case of schemes without hosts, relative URLs only work if the URL
- // starts with a single slash -- and canonicalization does not guarantee
- // this. The following cases all fail with TypeErrors.
- QCOMPARE(eval(QSL("new URL('bar', 'tst:foo').href")), QVariant());
- QCOMPARE(eval(QSL("new URL('baz', 'tst:foo/bar').href")), QVariant());
- QCOMPARE(eval(QSL("new URL('bar', 'tst://foo').href")), QVariant());
- QCOMPARE(eval(QSL("new URL('bar', 'tst:///foo').href")), QVariant());
-
- // However, registered custom schemes have been patched to allow relative
- // URLs even without an initial slash.
- QCOMPARE(eval(QSL("new URL('bar', 'qrc:foo').href")), QVariant(QSL("qrc:bar")));
- QCOMPARE(eval(QSL("new URL('baz', 'qrc:foo/bar').href")), QVariant(QSL("qrc:foo/baz")));
- QCOMPARE(eval(QSL("new URL('bar', 'qrc://foo').href")), QVariant());
- QCOMPARE(eval(QSL("new URL('bar', 'qrc:///foo').href")), QVariant());
-
- // With a slash it works the same as http except 'foo' is part of the path and not the host.
- QCOMPARE(eval(QSL("new URL('bar', 'qrc:/foo').href")), QVariant(QSL("qrc:/bar")));
- QCOMPARE(eval(QSL("new URL('bar', 'qrc:/foo/').href")), QVariant(QSL("qrc:/foo/bar")));
- QCOMPARE(eval(QSL("new URL('baz', 'qrc:/foo/bar').href")), QVariant(QSL("qrc:/foo/baz")));
- QCOMPARE(eval(QSL("new URL('baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/bar/baz")));
- QCOMPARE(eval(QSL("new URL('/baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz")));
- QCOMPARE(eval(QSL("new URL('./baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/bar/baz")));
- QCOMPARE(eval(QSL("new URL('../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/baz")));
- QCOMPARE(eval(QSL("new URL('../../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz")));
- QCOMPARE(eval(QSL("new URL('../../../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz")));
-
- // If the relative URL begins with >= 2 slashes, then the scheme is treated
- // not as a Syntax::Path scheme but as a Syntax::HostPortAndUserInformation
- // scheme.
- QCOMPARE(eval(QSL("new URL('//baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc://baz/")));
- QCOMPARE(eval(QSL("new URL('///baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc://baz/")));
-}
-
-// Test origin serialization in Blink, implemented by blink::KURL and
-// blink::SecurityOrigin as opposed to GURL and url::Origin.
-void tst_Origins::jsUrlOrigin()
-{
- QVERIFY(verifyLoad(QSL("about:blank")));
-
- // For network protocols the origin string must include the domain and port.
- QCOMPARE(eval(QSL("new URL(\"http://foo.com/page.html\").origin")), QVariant(QSL("http://foo.com")));
- QCOMPARE(eval(QSL("new URL(\"https://foo.com/page.html\").origin")), QVariant(QSL("https://foo.com")));
-
- // Even though file URL can also have domains, these are not included in the
- // origin string by Chromium. The standard does not specify a value here,
- // but suggests 'null' (https://url.spec.whatwg.org/#origin).
- QCOMPARE(eval(QSL("new URL(\"file:/etc/passwd\").origin")), QVariant(QSL("file://")));
- QCOMPARE(eval(QSL("new URL(\"file://foo.com/etc/passwd\").origin")), QVariant(QSL("file://")));
-
- // Unregistered schemes behave like file.
- QCOMPARE(eval(QSL("new URL(\"tst:/banana\").origin")), QVariant(QSL("tst://")));
- QCOMPARE(eval(QSL("new URL(\"tst://foo.com/banana\").origin")), QVariant(QSL("tst://")));
-
- // The non-PathSyntax schemes should have hosts and potentially ports.
- QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:41/bar\").origin")),
- QVariant(QSL("hostsyntax://foo")));
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").origin")),
- QVariant(QSL("hostandportsyntax://foo:41")));
- QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").origin")),
- QVariant(QSL("hostandportsyntax://foo")));
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").origin")),
- QVariant(QSL("hostportanduserinformationsyntax://foo:41")));
- QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").origin")),
- QVariant(QSL("hostportanduserinformationsyntax://foo")));
-
- // A PathSyntax scheme should have a 'universal' origin.
- QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")), QVariant(QSL("pathsyntax:")));
- QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc:")));
- QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc:")));
-
- // The NoAccessAllowed flag forces opaque origins.
- QCOMPARE(eval(QSL("new URL(\"PathSyntax-NoAccessAllowed:foo\").origin")),
- QVariant(QSL("null")));
-}
-
-class ScopedAttribute {
-public:
- ScopedAttribute(QWebEngineSettings *settings, QWebEngineSettings::WebAttribute attribute, bool newValue)
- : m_settings(settings)
- , m_attribute(attribute)
- , m_oldValue(m_settings->testAttribute(m_attribute))
- {
- m_settings->setAttribute(m_attribute, newValue);
- }
- ~ScopedAttribute()
- {
- m_settings->setAttribute(m_attribute, m_oldValue);
- }
-private:
- QWebEngineSettings *m_settings;
- QWebEngineSettings::WebAttribute m_attribute;
- bool m_oldValue;
-};
-
-// Test same-origin policy of file, qrc and custom schemes.
-//
-// Note the test case involves the main page trying to load an iframe from a
-// file that resides in a parent directory. This is just a small detail to
-// demonstrate the difference with Firefox where such access is not allowed.
-void tst_Origins::subdirWithAccess()
-{
- ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true);
-
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/subdir/index.html")));
- QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello")));
- QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world")));
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/subdir/index.html")));
- QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello")));
- QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world")));
-
- QVERIFY(verifyLoad(QSL("tst:/resources/subdir/index.html")));
- QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello")));
- QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world")));
-}
-
-// In this variation the LocalContentCanAccessFileUrls attribute is disabled. As
-// a result all file URLs will be considered to have unique/opaque origins, that
-// is, they are not the 'same origin as' any other origin.
-//
-// Note that this applies only to file URLs and not qrc or custom schemes.
-//
-// See also (in Blink):
-// - the allow_file_access_from_file_urls option and
-// - the blink::SecurityOrigin::BlockLocalAccessFromLocalOrigin() method.
-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());
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/subdir/index.html")));
- QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello")));
- QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world")));
-
- QVERIFY(verifyLoad(QSL("tst:/resources/subdir/index.html")));
- QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello")));
- QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world")));
-}
-
-// Load the main page over one scheme with an iframe over another scheme.
-//
-// For file and qrc schemes, the iframe should load but it should not be
-// possible for scripts in different frames to interact.
-//
-// Additionally for unregistered custom schemes and custom schemes without
-// LocalAccessAllowed it should not be possible to load an iframe over the
-// file: scheme.
-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')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
-
- 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")));
-}
-
-// Like mixedSchemes but adds a Content-Security-Policy: frame-src 'none' header.
-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")));
-}
-
-// Load the main page over one scheme, then make an XMLHttpRequest to a
-// different scheme.
-//
-// Cross-origin XMLHttpRequests can only be made to CORS-enabled schemes. These
-// include the builtin schemes http, https, data, and chrome, as well as custom
-// schemes with the CorsEnabled flag.
-void tst_Origins::mixedXHR()
-{
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/mixedXHR.html")));
- eval(QSL("sendXHR('file:" THIS_DIR "resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('qrc:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("error")));
- eval(QSL("sendXHR('tst:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("error")));
- eval(QSL("sendXHR('data:,ok')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('cors:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/mixedXHR.html")));
- eval(QSL("sendXHR('file:" THIS_DIR "resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('qrc:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('tst:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("error")));
- eval(QSL("sendXHR('data:,ok')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('cors:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-
- QVERIFY(verifyLoad(QSL("tst:/resources/mixedXHR.html")));
- eval(QSL("sendXHR('file:" THIS_DIR "resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("error")));
- eval(QSL("sendXHR('qrc:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("error")));
- eval(QSL("sendXHR('tst:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('data:,ok')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
- eval(QSL("sendXHR('cors:/resources/mixedXHR.txt')"));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-}
-
-#if defined(WEBSOCKETS)
-class EchoServer : public QObject {
- Q_OBJECT
- Q_PROPERTY(QUrl url READ url NOTIFY urlChanged)
-public:
- EchoServer() : webSocketServer(QSL("EchoServer"), QWebSocketServer::NonSecureMode)
- {
- connect(&webSocketServer, &QWebSocketServer::newConnection, this, &EchoServer::onNewConnection);
- }
-
- bool listen()
- {
- if (webSocketServer.listen(QHostAddress::Any)) {
- Q_EMIT urlChanged();
- return true;
- }
- return false;
- }
-
- QUrl url() const
- {
- return webSocketServer.serverUrl();
- }
-
-Q_SIGNALS:
- void urlChanged();
-
-private:
- void onNewConnection()
- {
- QWebSocket *socket = webSocketServer.nextPendingConnection();
- connect(socket, &QWebSocket::textMessageReceived, this, &EchoServer::onTextMessageReceived);
- connect(socket, &QWebSocket::disconnected, socket, &QObject::deleteLater);
- }
-
- void onTextMessageReceived(const QString &message)
- {
- QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
- socket->sendTextMessage(message);
- }
-
- QWebSocketServer webSocketServer;
-};
-
-// Try opening a WebSocket from pages loaded over various URL schemes.
-void tst_Origins::webSocket()
-{
- EchoServer echoServer;
- QWebChannel channel;
- channel.registerObject(QSL("echoServer"), &echoServer);
- m_page->setWebChannel(&channel);
- QVERIFY(echoServer.listen());
-
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/websocket.html")));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/websocket.html")));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-
- // Unregistered schemes can also open WebSockets (since Chromium 71)
- QVERIFY(verifyLoad(QSL("tst:/resources/websocket.html")));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-
- // Even an insecure registered scheme can open WebSockets.
- QVERIFY(verifyLoad(QSL("PathSyntax:/resources/websocket.html")));
- QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok")));
-}
-#endif
-// Create a (Dedicated)Worker. Since dedicated workers can only be accessed from
-// one page, there is not much need for security restrictions.
-void tst_Origins::dedicatedWorker()
-{
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/dedicatedWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/dedicatedWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- // Unregistered schemes can also create Workers (since Chromium 71)
- QVERIFY(verifyLoad(QSL("tst:/resources/dedicatedWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- // Even an insecure registered scheme can create Workers.
- QVERIFY(verifyLoad(QSL("PathSyntax:/resources/dedicatedWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- // But not if the NoAccessAllowed flag is set.
- QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/dedicatedWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("cannot be accessed from origin 'null'")));
-}
-
-// Create a SharedWorker. Shared workers can be accessed from multiple pages,
-// and therefore the same-origin policy applies.
-void tst_Origins::sharedWorker()
-{
- {
- ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false);
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/sharedWorker.html")));
- QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000);
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("cannot be accessed from origin 'null'")));
- }
-
- {
- ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true);
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/sharedWorker.html")));
- QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000);
- QCOMPARE(eval(QSL("result")), QVariant(42));
- }
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/sharedWorker.html")));
- QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000);
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- // Unregistered schemes should not create SharedWorkers.
-
- QVERIFY(verifyLoad(QSL("PathSyntax:/resources/sharedWorker.html")));
- QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000);
- QCOMPARE(eval(QSL("result")), QVariant(42));
-
- QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/sharedWorker.html")));
- QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000);
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("denied to origin 'null'")));
-}
-
-// Service workers have to be explicitly enabled for a scheme.
-void tst_Origins::serviceWorker()
-{
- QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('file://') is not supported.")));
-
- QVERIFY(verifyLoad(QSL("qrc:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('qrc:') is not supported.")));
-
- QVERIFY(verifyLoad(QSL("tst:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("Cannot read property 'register' of undefined")));
-
- QVERIFY(verifyLoad(QSL("PathSyntax:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("Cannot read property 'register' of undefined")));
-
- QVERIFY(verifyLoad(QSL("PathSyntax-Secure:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure:') is not supported.")));
-
- QVERIFY(verifyLoad(QSL("PathSyntax-ServiceWorkersAllowed:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("Cannot read property 'register' of undefined")));
-
- QVERIFY(verifyLoad(QSL("PathSyntax-Secure-ServiceWorkersAllowed:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QCOMPARE(eval(QSL("error")), QVariant());
-
- QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/serviceWorker.html")));
- QTRY_VERIFY(eval(QSL("done")).toBool());
- QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("Cannot read property 'register' of undefined")));
-}
-
-// Support for view-source must be enabled explicitly.
-void tst_Origins::viewSource()
-{
- QVERIFY(verifyLoad(QSL("view-source:file:" THIS_DIR "resources/viewSource.html")));
-#ifdef Q_OS_WIN
- QCOMPARE(m_page->requestedUrl().toString(), QSL("file:///" THIS_DIR "resources/viewSource.html"));
-#else
- QCOMPARE(m_page->requestedUrl().toString(), QSL("file://" THIS_DIR "resources/viewSource.html"));
-#endif
-
- QVERIFY(verifyLoad(QSL("view-source:qrc:/resources/viewSource.html")));
- QCOMPARE(m_page->requestedUrl().toString(), QSL("qrc:/resources/viewSource.html"));
-
- QVERIFY(verifyLoad(QSL("view-source:tst:/resources/viewSource.html")));
- QCOMPARE(m_page->requestedUrl().toString(), QSL("about:blank"));
-
- QVERIFY(verifyLoad(QSL("view-source:PathSyntax:/resources/viewSource.html")));
- QCOMPARE(m_page->requestedUrl().toString(), QSL("about:blank"));
-
- QVERIFY(verifyLoad(QSL("view-source:PathSyntax-ViewSourceAllowed:/resources/viewSource.html")));
- QCOMPARE(m_page->requestedUrl().toString(), QSL("pathsyntax-viewsourceallowed:/resources/viewSource.html"));
-}
-
-void tst_Origins::createObjectURL()
-{
- // Legal for registered custom schemes.
- QVERIFY(verifyLoad(QSL("qrc:/resources/createObjectURL.html")));
- QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:qrc:")));
-
- // Also legal for unregistered schemes (since Chromium 71)
- QVERIFY(verifyLoad(QSL("tst:/resources/createObjectURL.html")));
- QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:tst:")));
-}
-
-void tst_Origins::redirect()
-{
- QVERIFY(verifyLoad(QSL("redirect1:/resources/redirect.html")));
- QTRY_COMPARE(m_handler->requests().size(), 7);
- QCOMPARE(m_handler->requests()[0], QUrl(QStringLiteral("redirect1:/resources/redirect.html")));
- QCOMPARE(m_handler->requests()[1], QUrl(QStringLiteral("redirect2:/resources/redirect.html")));
- QCOMPARE(m_handler->requests()[2], QUrl(QStringLiteral("redirect1:/resources/redirect.css")));
- QCOMPARE(m_handler->requests()[3], QUrl(QStringLiteral("redirect2:/resources/redirect.css")));
- QCOMPARE(m_handler->requests()[4], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
- QCOMPARE(m_handler->requests()[5], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
- QCOMPARE(m_handler->requests()[6], QUrl(QStringLiteral("redirect2:/resources/Akronim-Regular.woff2")));
-}
-
-QTEST_MAIN(tst_Origins)
-#include "tst_origins.moc"
diff --git a/tests/auto/widgets/origins/tst_origins.qrc b/tests/auto/widgets/origins/tst_origins.qrc
deleted file mode 100644
index fcf54aaea..000000000
--- a/tests/auto/widgets/origins/tst_origins.qrc
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
-<qresource>
- <file>resources/createObjectURL.html</file>
- <file>resources/dedicatedWorker.html</file>
- <file>resources/dedicatedWorker.js</file>
- <file>resources/mixedSchemes.html</file>
- <file>resources/mixedSchemesWithCsp.html</file>
- <file>resources/mixedSchemes_frame.html</file>
- <file>resources/mixedXHR.html</file>
- <file>resources/mixedXHR.txt</file>
- <file>resources/serviceWorker.html</file>
- <file>resources/serviceWorker.js</file>
- <file>resources/sharedWorker.html</file>
- <file>resources/sharedWorker.js</file>
- <file>resources/subdir/frame2.html</file>
- <file>resources/subdir/index.html</file>
- <file>resources/subdir_frame1.html</file>
- <file>resources/viewSource.html</file>
- <file>resources/websocket.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/printing/CMakeLists.txt b/tests/auto/widgets/printing/CMakeLists.txt
new file mode 100644
index 000000000..baa3cf747
--- /dev/null
+++ b/tests/auto/widgets/printing/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+find_package(PkgConfig)
+if(PkgConfig_FOUND)
+ pkg_check_modules(POPPLER_CPP poppler-cpp IMPORTED_TARGET)
+endif()
+
+qt_internal_add_test(tst_printing
+ SOURCES
+ tst_printing.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::WebEngineWidgets
+ Qt::WebEngineCorePrivate
+ Test::Util
+)
+
+qt_internal_extend_target(tst_printing
+ CONDITION POPPLER_CPP_FOUND AND QT_FEATURE_webengine_system_poppler
+ LIBRARIES
+ PkgConfig::POPPLER_CPP
+)
+
+set(tst_printing_resource_files
+ "resources/basic_printing_page.html"
+)
+
+qt_internal_add_resource(tst_printing "tst_printing"
+ PREFIX "/"
+ FILES ${tst_printing_resource_files}
+)
diff --git a/tests/auto/widgets/printing/printing.pro b/tests/auto/widgets/printing/printing.pro
deleted file mode 100644
index 92f5d611c..000000000
--- a/tests/auto/widgets/printing/printing.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093
-QT_FOR_CONFIG += webenginecore-private
-
-include(../tests.pri)
-QT *= core-private webenginecore-private
-
-qtConfig(webengine-poppler-cpp) {
- CONFIG += link_pkgconfig
- PKGCONFIG += poppler-cpp
-}
diff --git a/tests/auto/widgets/printing/tst_printing.cpp b/tests/auto/widgets/printing/tst_printing.cpp
index 380fb65ff..605fb57b5 100644
--- a/tests/auto/widgets/printing/tst_printing.cpp
+++ b/tests/auto/widgets/printing/tst_printing.cpp
@@ -1,39 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
-#include <QWebEnginePage>
+#include <QtWebEngineCore/qtwebenginecore-config.h>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
#include <QTemporaryDir>
#include <QTest>
#include <QSignalSpy>
#include <util.h>
-#if QT_CONFIG(webengine_poppler_cpp)
+#if QT_CONFIG(webengine_system_poppler)
#include <poppler-document.h>
#include <poppler-page.h>
#endif
@@ -44,25 +21,27 @@ class tst_Printing : public QObject
private slots:
void printToPdfBasic();
void printRequest();
-#if QT_CONFIG(webengine_poppler_cpp) && defined(Q_OS_LINUX) && defined(__GLIBCXX__)
+#if QT_CONFIG(webengine_system_poppler)
void printToPdfPoppler();
+ void printFromPdfViewer();
#endif
+ void interruptPrinting();
};
void tst_Printing::printToPdfBasic()
{
QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX");
QVERIFY(tempDir.isValid());
- QWebEnginePage page;
- QSignalSpy spy(&page, &QWebEnginePage::loadFinished);
- page.load(QUrl("qrc:///resources/basic_printing_page.html"));
- QTRY_VERIFY(spy.count() == 1);
+ QWebEngineView view;
+ QSignalSpy spy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("qrc:///resources/basic_printing_page.html"));
+ QTRY_VERIFY(spy.size() == 1);
- QSignalSpy savePdfSpy(&page, &QWebEnginePage::pdfPrintingFinished);
+ QSignalSpy savePdfSpy(view.page(), &QWebEnginePage::pdfPrintingFinished);
QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0));
QString path = tempDir.path() + "/print_1_success.pdf";
- page.printToPdf(path, layout);
- QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal");
+ view.page()->printToPdf(path, layout);
+ QTRY_VERIFY2(savePdfSpy.size() == 1, "Printing to PDF file failed without signal");
QList<QVariant> successArguments = savePdfSpy.takeFirst();
QVERIFY2(successArguments.at(0).toString() == path, "File path for first saved PDF does not match arguments");
@@ -73,56 +52,58 @@ void tst_Printing::printToPdfBasic()
#else
path = tempDir.path() + "/print_|2_failed.pdf";
#endif
- page.printToPdf(path, QPageLayout());
- QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal");
+ view.page()->printToPdf(path, QPageLayout());
+ QTRY_VERIFY2(savePdfSpy.size() == 1, "Printing to PDF file failed without signal");
QList<QVariant> failedArguments = savePdfSpy.takeFirst();
QVERIFY2(failedArguments.at(0).toString() == path, "File path for second saved PDF does not match arguments");
QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail");
CallbackSpy<QByteArray> successfulSpy;
- page.printToPdf(successfulSpy.ref(), layout);
- QVERIFY(successfulSpy.waitForResult().length() > 0);
+ view.page()->printToPdf(successfulSpy.ref(), layout);
+ QVERIFY(successfulSpy.waitForResult().size() > 0);
CallbackSpy<QByteArray> failedInvalidLayoutSpy;
- page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout());
- QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0);
+ view.page()->printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout());
+ QCOMPARE(failedInvalidLayoutSpy.waitForResult().size(), 0);
}
void tst_Printing::printRequest()
{
- QWebEnginePage webPage;
+ QWebEngineView view;
QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0));
- QSignalSpy loadFinishedSpy(&webPage, &QWebEnginePage::loadFinished);
- QSignalSpy printRequestedSpy(&webPage, &QWebEnginePage::printRequested);
- QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished);
+ QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished);
+ QSignalSpy printRequestedSpy(&view, &QWebEngineView::printRequested);
+ QSignalSpy printRequestedSpy2(view.page(), &QWebEnginePage::printRequested);
+ QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished);
CallbackSpy<QByteArray> resultSpy;
- webPage.load(QUrl("qrc:///resources/basic_printing_page.html"));
- QTRY_VERIFY(loadFinishedSpy.count() == 1);
- webPage.runJavaScript("window.print()");
- QTRY_VERIFY(printRequestedSpy.count() == 1);
+ view.load(QUrl("qrc:///resources/basic_printing_page.html"));
+ QTRY_VERIFY(loadFinishedSpy.size() == 1);
+ view.page()->runJavaScript("window.print()");
+ QTRY_VERIFY(printRequestedSpy.size() == 1);
+ QVERIFY(printRequestedSpy2.size() == 1);
//check if printing still works
- webPage.printToPdf(resultSpy.ref(), layout);
+ view.printToPdf(resultSpy.ref(), layout);
const QByteArray data = resultSpy.waitForResult();
- QVERIFY(data.length() > 0);
+ QVERIFY(data.size() > 0);
}
-#if QT_CONFIG(webengine_poppler_cpp) && defined(Q_OS_LINUX) && defined(__GLIBCXX__)
+#if QT_CONFIG(webengine_system_poppler)
void tst_Printing::printToPdfPoppler()
{
// check if generated pdf is correct by searching for a know string on the page
using namespace poppler;
- QWebEnginePage webPage;
+ QWebEngineView view;
QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0));
- QSignalSpy spy(&webPage, &QWebEnginePage::loadFinished);
- QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished);
+ QSignalSpy spy(&view, &QWebEngineView::loadFinished);
+ QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished);
CallbackSpy<QByteArray> resultSpy;
- webPage.load(QUrl("qrc:///resources/basic_printing_page.html"));
+ view.load(QUrl("qrc:///resources/basic_printing_page.html"));
QTRY_VERIFY(spy.count() == 1);
- webPage.printToPdf(resultSpy.ref(), layout);
+ view.printToPdf(resultSpy.ref(), layout);
const QByteArray data = resultSpy.waitForResult();
QVERIFY(data.length() > 0);
@@ -137,8 +118,65 @@ void tst_Printing::printToPdfPoppler()
QVERIFY2(pdfPage->search(ustring::from_latin1("Hello Paper World"), rect, page::search_from_top,
case_sensitive ), "Could not find text");
}
+
+void tst_Printing::printFromPdfViewer()
+{
+ using namespace poppler;
+
+ QWebEngineView view;
+ view.page()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
+ view.page()->settings()->setAttribute(QWebEngineSettings::PdfViewerEnabled, true);
+
+ // Load a basic HTML
+ QSignalSpy spy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("qrc:///resources/basic_printing_page.html"));
+ QTRY_COMPARE(spy.size(), 1);
+
+ // Create a PDF
+ QTemporaryDir tempDir(QDir::tempPath() + "/tst_printing-XXXXXX");
+ QVERIFY(tempDir.isValid());
+ QString path = tempDir.path() + "/basic_page.pdf";
+ QSignalSpy savePdfSpy(view.page(), &QWebEnginePage::pdfPrintingFinished);
+ view.page()->printToPdf(path);
+ QTRY_COMPARE(savePdfSpy.size(), 1);
+
+ // Open the new file with the PDF viewer plugin
+ view.load(QUrl("file://" + path));
+ QTRY_COMPARE(spy.size(), 2);
+
+ // Print from the plugin
+ // loadFinished signal is not reliable when loading a PDF file, because it has multiple phases.
+ // Workaround: Try to print it a couple of times until the result matches the expected.
+ CallbackSpy<QByteArray> resultSpy;
+ bool ok = QTest::qWaitFor([&]() -> bool {
+ view.printToPdf(resultSpy.ref());
+ QByteArray data = resultSpy.waitForResult();
+
+ // Check if the result contains text from the original basic HTML
+ // This catches all the typical issues: empty result or printing the WebUI without PDF content.
+ QScopedPointer<document> pdf(document::load_from_raw_data(data.constData(), data.length()));
+ QScopedPointer<page> pdfPage(pdf->create_page(0));
+ rectf rect;
+ return pdfPage->search(ustring::from_latin1("Hello Paper World"), rect, page::search_from_top,
+ case_sensitive);
+ }, 10000);
+ QVERIFY(ok);
+}
#endif
+void tst_Printing::interruptPrinting()
+{
+ QWebEngineView view;
+ QSignalSpy spy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("qrc:///resources/basic_printing_page.html"));
+ QTRY_VERIFY(spy.size() == 1);
+
+ QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX");
+ QVERIFY(tempDir.isValid());
+ view.page()->printToPdf(tempDir.path() + "/file.pdf");
+ // Navigation stop interrupts print job, preferably do this without crash/assert
+ view.page()->triggerAction(QWebEnginePage::Stop);
+}
QTEST_MAIN(tst_Printing)
#include "tst_printing.moc"
diff --git a/tests/auto/widgets/printing/tst_printing.qrc b/tests/auto/widgets/printing/tst_printing.qrc
deleted file mode 100644
index b1795ef8a..000000000
--- a/tests/auto/widgets/printing/tst_printing.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/basic_printing_page.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/proxy/CMakeLists.txt b/tests/auto/widgets/proxy/CMakeLists.txt
new file mode 100644
index 000000000..95dc903ed
--- /dev/null
+++ b/tests/auto/widgets/proxy/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+
+qt_internal_add_test(tst_webengine_proxy
+ SOURCES
+ tst_proxy.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::HttpServer
+)
diff --git a/tests/auto/widgets/proxy/proxy.pro b/tests/auto/widgets/proxy/proxy.pro
deleted file mode 100644
index 802dfad05..000000000
--- a/tests/auto/widgets/proxy/proxy.pro
+++ /dev/null
@@ -1,9 +0,0 @@
-include(../tests.pri)
-QT += core-private webengine webengine-private
-
-HEADERS += \
- proxy_server.h
-
-SOURCES += \
- proxy_server.cpp
-
diff --git a/tests/auto/widgets/proxy/proxy_server.cpp b/tests/auto/widgets/proxy/proxy_server.cpp
deleted file mode 100644
index 3bf915609..000000000
--- a/tests/auto/widgets/proxy/proxy_server.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "proxy_server.h"
-#include <QDataStream>
-#include <QTcpSocket>
-#include <QDebug>
-
-ProxyServer::ProxyServer(QObject *parent) : QObject(parent)
-{
- connect(&m_server, &QTcpServer::newConnection, this, &ProxyServer::handleNewConnection);
-}
-
-void ProxyServer::setCredentials(const QByteArray &user, const QByteArray password)
-{
- m_auth.append(user);
- m_auth.append(QChar(':'));
- m_auth.append(password);
- m_auth = m_auth.toBase64();
- m_authenticate = true;
-}
-
-void ProxyServer::setCookie(const QByteArray &cookie)
-{
- m_cookie.append(QByteArrayLiteral("Cookie: "));
- m_cookie.append(cookie);
-}
-
-
-bool ProxyServer::isListening()
-{
- return m_server.isListening();
-}
-
-void ProxyServer::run()
-{
- if (!m_server.listen(QHostAddress::LocalHost, 5555))
- qFatal("Could not start the test server");
-}
-
-void ProxyServer::handleNewConnection()
-{
- // do one connection at the time
- Q_ASSERT(m_data.isEmpty());
- QTcpSocket *socket = m_server.nextPendingConnection();
- Q_ASSERT(socket);
- connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater);
- connect(socket, &QAbstractSocket::readyRead, this, &ProxyServer::handleReadReady);
-}
-
-void ProxyServer::handleReadReady()
-{
- QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
- Q_ASSERT(socket);
-
- m_data.append(socket->readAll());
-
- if (!m_data.endsWith("\r\n\r\n"))
- return;
-
- if (m_authenticate && !m_data.contains(QByteArrayLiteral("Proxy-Authorization: Basic"))) {
- socket->write("HTTP/1.1 407 Proxy Authentication Required\nProxy-Authenticate: "
- "Basic realm=\"Proxy requires authentication\"\r\n"
- "content-length: 0\r\n"
- "\r\n");
- return;
- }
-
- if (m_authenticate && m_data.contains(m_auth)) {
- emit authenticationSuccess();
- }
-
- if (m_data.contains(m_cookie)) {
- emit cookieMatch();
- }
- m_data.clear();
-}
diff --git a/tests/auto/widgets/proxy/proxy_server.h b/tests/auto/widgets/proxy/proxy_server.h
deleted file mode 100644
index 7bc7b100b..000000000
--- a/tests/auto/widgets/proxy/proxy_server.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef PROXY_SERVER_H
-#define PROXY_SERVER_H
-
-#include <QObject>
-#include <QTcpServer>
-
-class ProxyServer : public QObject
-{
- Q_OBJECT
-
-public:
- explicit ProxyServer(QObject *parent = nullptr);
- void setCredentials(const QByteArray &user, const QByteArray password);
- void setCookie(const QByteArray &cookie);
- bool isListening();
-
-public slots:
- void run();
-
-private slots:
- void handleNewConnection();
- void handleReadReady();
-
-signals:
- void authenticationSuccess();
- void cookieMatch();
-
-private:
- QByteArray m_data;
- QTcpServer m_server;
- QByteArray m_auth;
- QByteArray m_cookie;
- bool m_authenticate = false;
-};
-
-#endif // PROXY_SERVER_H
diff --git a/tests/auto/widgets/proxy/tst_proxy.cpp b/tests/auto/widgets/proxy/tst_proxy.cpp
index c3e3c88a4..3dc72618c 100644
--- a/tests/auto/widgets/proxy/tst_proxy.cpp
+++ b/tests/auto/widgets/proxy/tst_proxy.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "proxy_server.h"
#include <QTest>
@@ -33,7 +8,7 @@
#include <QWebEnginePage>
#include <QWebEngineView>
#include <QWebEngineUrlRequestInterceptor>
-
+#include <QWebEngineLoadingInfo>
struct Interceptor : public QWebEngineUrlRequestInterceptor
{
@@ -53,6 +28,7 @@ public:
private slots:
void proxyAuthentication();
void forwardCookie();
+ void invalidHostName();
};
@@ -74,7 +50,7 @@ void tst_Proxy::proxyAuthentication()
QWebEnginePage page;
QSignalSpy successSpy(&server, &ProxyServer::authenticationSuccess);
page.load(QUrl("http://www.qt.io"));
- QTRY_VERIFY2(successSpy.count() > 0, "Could not get authentication token");
+ QTRY_VERIFY2(successSpy.size() > 0, "Could not get authentication token");
}
void tst_Proxy::forwardCookie()
@@ -94,7 +70,20 @@ void tst_Proxy::forwardCookie()
page.setUrlRequestInterceptor(&interceptor);
QSignalSpy cookieSpy(&server, &ProxyServer::cookieMatch);
page.load(QUrl("http://www.qt.io"));
- QTRY_VERIFY2(cookieSpy.count() > 0, "Could not get cookie");
+ QTRY_VERIFY2(cookieSpy.size() > 0, "Could not get cookie");
+}
+
+// Crash test ( https://bugreports.qt.io/browse/QTBUG-113992 )
+void tst_Proxy::invalidHostName()
+{
+ QNetworkProxy proxy;
+ proxy.setType(QNetworkProxy::HttpProxy);
+ proxy.setHostName("999.0.0.0");
+ QNetworkProxy::setApplicationProxy(proxy);
+ QWebEnginePage page;
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+ page.load(QUrl("http://www.qt.io"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);
}
#include "tst_proxy.moc"
diff --git a/tests/auto/widgets/proxypac/CMakeLists.txt b/tests/auto/widgets/proxypac/CMakeLists.txt
new file mode 100644
index 000000000..f27160cb6
--- /dev/null
+++ b/tests/auto/widgets/proxypac/CMakeLists.txt
@@ -0,0 +1,64 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+
+qt_internal_add_test(tst_proxypac_file
+ SOURCES
+ tst_proxypac.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+ Test::HttpServer
+)
+
+if(WIN32)
+ get_filename_component(SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
+ set(fileEnvArg "--proxy-pac-url=\"file:///${SOURCE_DIR}/proxy.pac\"")
+elseif(LINUX AND CMAKE_CROSSCOMPILING)
+ set(fileEnvArg "--single-process --no-sandbox --proxy-pac-url=\"file://${CMAKE_CURRENT_LIST_DIR}/proxy.pac\"")
+else()
+ set(fileEnvArg "--proxy-pac-url=\"file://${CMAKE_CURRENT_LIST_DIR}/proxy.pac\"")
+endif()
+
+set_tests_properties(tst_proxypac_file PROPERTIES
+ ENVIRONMENT QTWEBENGINE_CHROMIUM_FLAGS=${fileEnvArg}
+)
+
+if(NOT (LINUX AND CMAKE_CROSSCOMPILING))
+ set(fileEnvArg "--single-process ${fileEnvArg}")
+
+ qt_internal_add_test(tst_proxypac_single_process
+ SOURCES
+ tst_proxypac.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+ Test::HttpServer
+ )
+
+ set_tests_properties(tst_proxypac_single_process PROPERTIES
+ ENVIRONMENT QTWEBENGINE_CHROMIUM_FLAGS=${fileEnvArg}
+ )
+endif()
+
+qt_internal_add_test(tst_proxypac_qrc
+ SOURCES
+ tst_proxypac.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+ Test::HttpServer
+)
+
+if(LINUX AND CMAKE_CROSSCOMPILING)
+ set(qrcEnvArg "--single-process --no-sandbox --proxy-pac-url=\"qrc:///proxy.pac\"")
+else()
+ set(qrcEnvArg "--proxy-pac-url=\"qrc:///proxy.pac\"")
+endif()
+
+set_tests_properties(tst_proxypac_qrc PROPERTIES
+ ENVIRONMENT QTWEBENGINE_CHROMIUM_FLAGS=${qrcEnvArg}
+)
+
+qt_internal_add_resource(tst_proxypac_qrc "proxypac"
+ PREFIX "/"
+ FILES "proxy.pac"
+)
diff --git a/tests/auto/widgets/proxypac/proxy.pac b/tests/auto/widgets/proxypac/proxy.pac
index 1d29847b9..966c37ba5 100644
--- a/tests/auto/widgets/proxypac/proxy.pac
+++ b/tests/auto/widgets/proxypac/proxy.pac
@@ -2,6 +2,6 @@ function FindProxyForURL(url, host)
{
if (shExpMatch(host, "*.proxy1.com")) return "PROXY localhost:5551";
if (shExpMatch(host, "*.proxy2.com")) return "PROXY localhost:5552";
- return "PROXY proxy.url:8080";
+ return "DIRECT";
}
diff --git a/tests/auto/widgets/proxypac/proxypac.pri b/tests/auto/widgets/proxypac/proxypac.pri
deleted file mode 100644
index b3b2856c8..000000000
--- a/tests/auto/widgets/proxypac/proxypac.pri
+++ /dev/null
@@ -1,5 +0,0 @@
-TEMPLATE = app
-CONFIG += testcase
-QT += testlib network webenginewidgets webengine
-HEADERS += $$PWD/proxyserver.h
-SOURCES += $$PWD/proxyserver.cpp $$PWD/tst_proxypac.cpp
diff --git a/tests/auto/widgets/proxypac/proxypac.pro b/tests/auto/widgets/proxypac/proxypac.pro
deleted file mode 100644
index f2a43d41f..000000000
--- a/tests/auto/widgets/proxypac/proxypac.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = proxypac_file proxypac_qrc
-CONFIG += ordered
-
diff --git a/tests/auto/widgets/proxypac/proxypac.qrc b/tests/auto/widgets/proxypac/proxypac.qrc
deleted file mode 100644
index 9047585a0..000000000
--- a/tests/auto/widgets/proxypac/proxypac.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
-<qresource profix="/">
- <file>proxy.pac</file>
-</qresource>
-</RCC>
-
diff --git a/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro b/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro
deleted file mode 100644
index 037123054..000000000
--- a/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro
+++ /dev/null
@@ -1,9 +0,0 @@
-include(../proxypac.pri)
-
-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"
-
-QT_TOOL_ENV += proxy_pac
-
diff --git a/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro b/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro
deleted file mode 100644
index a5ab64605..000000000
--- a/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-include(../proxypac.pri)
-
-proxy_pac.name = QTWEBENGINE_CHROMIUM_FLAGS
-proxy_pac.value = --proxy-pac-url="qrc:///proxy.pac"
-boot2qt:proxy_pac.value = "--single-process --no-sandbox --proxy-pac-url=qrc:///proxy.pac"
-QT_TOOL_ENV += proxy_pac
-RESOURCES+= $$PWD/../proxypac.qrc
diff --git a/tests/auto/widgets/proxypac/proxyserver.cpp b/tests/auto/widgets/proxypac/proxyserver.cpp
index 4d38c87c9..f7a859747 100644
--- a/tests/auto/widgets/proxypac/proxyserver.cpp
+++ b/tests/auto/widgets/proxypac/proxyserver.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "proxyserver.h"
#include <QDataStream>
diff --git a/tests/auto/widgets/proxypac/proxyserver.h b/tests/auto/widgets/proxypac/proxyserver.h
index ea68286a2..c95856da9 100644
--- a/tests/auto/widgets/proxypac/proxyserver.h
+++ b/tests/auto/widgets/proxypac/proxyserver.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PROXY_SERVER_H
#define PROXY_SERVER_H
diff --git a/tests/auto/widgets/proxypac/tst_proxypac.cpp b/tests/auto/widgets/proxypac/tst_proxypac.cpp
index 934e23fde..43ccbf028 100644
--- a/tests/auto/widgets/proxypac/tst_proxypac.cpp
+++ b/tests/auto/widgets/proxypac/tst_proxypac.cpp
@@ -1,40 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include "qtwebengineglobal.h"
-#include "proxyserver.h"
+#include "proxy_server.h"
#include <QTest>
#include <QSignalSpy>
#include <QWebEngineProfile>
#include <QWebEnginePage>
#include <QNetworkProxy>
-
class tst_ProxyPac : public QObject {
Q_OBJECT
public:
@@ -46,30 +19,39 @@ private slots:
void tst_ProxyPac::proxypac()
{
- const QString fromEnv = QString::fromLocal8Bit(qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
+ const QString fromEnv = qEnvironmentVariable("QTWEBENGINE_CHROMIUM_FLAGS");
if (!fromEnv.contains("--proxy-pac-url"))
- qFatal("--proxy-pac-url argument is not passed.");
+ qFatal("--proxy-pac-url argument is not passed. Use ctest or set QTWEBENGINE_CHROMIUM_FLAGS");
ProxyServer proxyServer1;
+ QSignalSpy proxySpy1(&proxyServer1, &ProxyServer::requestReceived);
proxyServer1.setPort(5551);
proxyServer1.run();
- QSignalSpy proxySpy1(&proxyServer1, &ProxyServer::requestReceived);
ProxyServer proxyServer2;
+ QSignalSpy proxySpy2(&proxyServer2, &ProxyServer::requestReceived);
proxyServer2.setPort(5552);
proxyServer2.run();
- QSignalSpy proxySpy2(&proxyServer2, &ProxyServer::requestReceived);
QTRY_VERIFY2(proxyServer1.isListening(), "Could not setup proxy server 1");
QTRY_VERIFY2(proxyServer2.isListening(), "Could not setup proxy server 2");
QWebEngineProfile profile;
QWebEnginePage page(&profile);
+
+ const bool v8_proxy_resolver_enabled = !fromEnv.contains("--single-process");
page.load(QUrl("http://test.proxy1.com"));
- QTRY_COMPARE(proxySpy1.count() >= 1, true);
- QVERIFY(proxySpy2.count() == 0);
+ QTRY_COMPARE(proxySpy1.size() >= 1, v8_proxy_resolver_enabled);
+ QVERIFY(proxySpy2.size() == 0);
page.load(QUrl("http://test.proxy2.com"));
- QTRY_COMPARE(proxySpy2.count() >= 1 , true);
+ QTRY_COMPARE(proxySpy2.size() >= 1, v8_proxy_resolver_enabled);
+
+ // check for crash
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+ page.load(QUrl("https://contribute.qt-project.org"));
+
+ QTRY_VERIFY_WITH_TIMEOUT(!spyFinished.isEmpty(), 200000);
+
}
#include "tst_proxypac.moc"
diff --git a/tests/auto/widgets/qtbug_110287/CMakeLists.txt b/tests/auto/widgets/qtbug_110287/CMakeLists.txt
new file mode 100644
index 000000000..ac7926dc0
--- /dev/null
+++ b/tests/auto/widgets/qtbug_110287/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qtbug_110287
+ SOURCES
+ tst_qtbug_110287.cpp
+ LIBRARIES
+ Qt::Network
+ Qt::WebEngineWidgets
+)
+target_link_options(tst_qtbug_110287 PRIVATE "-Wl,--as-needed")
diff --git a/tests/auto/widgets/qtbug_110287/tst_qtbug_110287.cpp b/tests/auto/widgets/qtbug_110287/tst_qtbug_110287.cpp
new file mode 100644
index 000000000..9453ae9b8
--- /dev/null
+++ b/tests/auto/widgets/qtbug_110287/tst_qtbug_110287.cpp
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QSignalSpy>
+#include <QTest>
+#include <QWebEngineView>
+
+class tst_qtbug_110287 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qtbug_110287() { }
+
+private slots:
+ void getAddrInfo();
+};
+
+void tst_qtbug_110287::getAddrInfo()
+{
+ QNetworkAccessManager nam;
+ QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished);
+
+ QString address("http://www.example.com");
+ QScopedPointer<QNetworkReply> reply(nam.get(QNetworkRequest(address)));
+
+ if (!namSpy.wait(25000) || reply->error() != QNetworkReply::NoError)
+ QSKIP("Couldn't load page from network, skipping test.");
+
+ QWebEngineView view;
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+
+ // load() will trigger system DNS resolution that uses getaddrinfo()
+ view.load(QUrl(address));
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size() > 0, true, 30000);
+ QTRY_COMPARE(loadFinishedSpy[0][0].toBool(), true);
+}
+
+#include "tst_qtbug_110287.moc"
+QTEST_MAIN(tst_qtbug_110287)
diff --git a/tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro b/tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro
deleted file mode 100644
index 18a66c466..000000000
--- a/tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-include(../tests.pri)
-include(../../shared/http.pri)
-QT *= core-private
diff --git a/tests/auto/widgets/qwebenginedownloadrequest/CMakeLists.txt b/tests/auto/widgets/qwebenginedownloadrequest/CMakeLists.txt
new file mode 100644
index 000000000..5b76909b1
--- /dev/null
+++ b/tests/auto/widgets/qwebenginedownloadrequest/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebenginedownloadrequest
+ SOURCES
+ tst_qwebenginedownloadrequest.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::HttpServer
+ Test::Util
+)
diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloadrequest/tst_qwebenginedownloadrequest.cpp
index 39948c211..c81a27b3a 100644
--- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
+++ b/tests/auto/widgets/qwebenginedownloadrequest/tst_qwebenginedownloadrequest.cpp
@@ -1,30 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <util.h>
#include <QCoreApplication>
#include <QSignalSpy>
@@ -32,14 +9,14 @@
#include <QTemporaryDir>
#include <QTest>
#include <QRegularExpression>
-#include <QWebEngineDownloadItem>
+#include <QWebEngineDownloadRequest>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QWebEngineSettings>
#include <QWebEngineView>
#include <httpserver.h>
-class tst_QWebEngineDownloadItem : public QObject
+class tst_QWebEngineDownloadRequest : public QObject
{
Q_OBJECT
@@ -77,53 +54,40 @@ private Q_SLOTS:
void downloadToDefaultLocation();
void downloadToNonExistentDir();
void downloadToReadOnlyDir();
-#if QT_DEPRECATED_SINCE(5, 14)
- void downloadPathValidation();
-#endif
void downloadToDirectoryWithFileName_data();
void downloadToDirectoryWithFileName();
+ void downloadDataUrls_data();
+ void downloadDataUrls();
private:
void saveLink(QPoint linkPos);
void clickLink(QPoint linkPos);
void simulateUserAction(QPoint linkPos, UserAction action);
- QWebEngineDownloadItem::DownloadType expectedDownloadType(
- UserAction userAction,
- const QByteArray &contentDisposition = QByteArray());
-
HttpServer *m_server;
QWebEngineProfile *m_profile;
QWebEnginePage *m_page;
QWebEngineView *m_view;
- QSet<QWebEngineDownloadItem *> m_requestedDownloads;
- QSet<QWebEngineDownloadItem *> m_finishedDownloads;
-};
-
-class ScopedConnection {
-public:
- ScopedConnection(QMetaObject::Connection connection) : m_connection(std::move(connection)) {}
- ~ScopedConnection() { QObject::disconnect(m_connection); }
-private:
- QMetaObject::Connection m_connection;
+ QSet<QWebEngineDownloadRequest *> m_requestedDownloads;
+ QSet<QWebEngineDownloadRequest *> m_finishedDownloads;
};
-Q_DECLARE_METATYPE(tst_QWebEngineDownloadItem::UserAction)
-Q_DECLARE_METATYPE(tst_QWebEngineDownloadItem::FileAction)
+Q_DECLARE_METATYPE(tst_QWebEngineDownloadRequest::UserAction)
+Q_DECLARE_METATYPE(tst_QWebEngineDownloadRequest::FileAction)
-void tst_QWebEngineDownloadItem::initTestCase()
+void tst_QWebEngineDownloadRequest::initTestCase()
{
m_server = new HttpServer();
m_profile = new QWebEngineProfile;
m_profile->setHttpCacheType(QWebEngineProfile::NoCache);
m_profile->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false);
- connect(m_profile, &QWebEngineProfile::downloadRequested, [this](QWebEngineDownloadItem *item) {
+ connect(m_profile, &QWebEngineProfile::downloadRequested, [this](QWebEngineDownloadRequest *item) {
m_requestedDownloads.insert(item);
- connect(item, &QWebEngineDownloadItem::destroyed, [this, item](){
+ connect(item, &QWebEngineDownloadRequest::destroyed, [this, item](){
m_requestedDownloads.remove(item);
m_finishedDownloads.remove(item);
});
- connect(item, &QWebEngineDownloadItem::finished, [this, item](){
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [this, item](){
m_finishedDownloads.insert(item);
});
});
@@ -134,24 +98,24 @@ void tst_QWebEngineDownloadItem::initTestCase()
m_view->show();
}
-void tst_QWebEngineDownloadItem::init()
+void tst_QWebEngineDownloadRequest::init()
{
QVERIFY(m_server->start());
}
-void tst_QWebEngineDownloadItem::cleanup()
+void tst_QWebEngineDownloadRequest::cleanup()
{
- for (QWebEngineDownloadItem *item : m_finishedDownloads) {
+ for (QWebEngineDownloadRequest *item : m_finishedDownloads) {
item->deleteLater();
}
- QTRY_COMPARE(m_requestedDownloads.count(), 0);
- QCOMPARE(m_finishedDownloads.count(), 0);
+ QTRY_COMPARE(m_requestedDownloads.size(), 0);
+ QCOMPARE(m_finishedDownloads.size(), 0);
QVERIFY(m_server->stop());
// Set download path to default.
m_profile->setDownloadPath("");
}
-void tst_QWebEngineDownloadItem::cleanupTestCase()
+void tst_QWebEngineDownloadRequest::cleanupTestCase()
{
delete m_view;
delete m_page;
@@ -159,24 +123,27 @@ void tst_QWebEngineDownloadItem::cleanupTestCase()
delete m_server;
}
-void tst_QWebEngineDownloadItem::saveLink(QPoint linkPos)
+void tst_QWebEngineDownloadRequest::saveLink(QPoint linkPos)
{
// Simulate right-clicking on link and choosing "save link as" from menu.
QSignalSpy menuSpy(m_view, &QWebEngineView::customContextMenuRequested);
m_view->setContextMenuPolicy(Qt::CustomContextMenu);
- auto event1 = new QContextMenuEvent(QContextMenuEvent::Mouse, linkPos);
- auto event2 = new QMouseEvent(QEvent::MouseButtonPress, linkPos, Qt::RightButton, {}, {});
- auto event3 = new QMouseEvent(QEvent::MouseButtonRelease, linkPos, Qt::RightButton, {}, {});
+ auto event1 =
+ new QContextMenuEvent(QContextMenuEvent::Mouse, linkPos, m_view->mapToGlobal(linkPos));
+ auto event2 = new QMouseEvent(QEvent::MouseButtonPress, linkPos, m_view->mapToGlobal(linkPos),
+ Qt::RightButton, {}, {});
+ auto event3 = new QMouseEvent(QEvent::MouseButtonRelease, linkPos, m_view->mapToGlobal(linkPos),
+ Qt::RightButton, {}, {});
QTRY_VERIFY(m_view->focusWidget());
QWidget *renderWidget = m_view->focusWidget();
QCoreApplication::postEvent(renderWidget, event1);
QCoreApplication::postEvent(renderWidget, event2);
QCoreApplication::postEvent(renderWidget, event3);
- QTRY_COMPARE(menuSpy.count(), 1);
+ QTRY_COMPARE(menuSpy.size(), 1);
m_page->triggerAction(QWebEnginePage::DownloadLinkToDisk);
}
-void tst_QWebEngineDownloadItem::clickLink(QPoint linkPos)
+void tst_QWebEngineDownloadRequest::clickLink(QPoint linkPos)
{
// Simulate left-clicking on link.
QTRY_VERIFY(m_view->focusWidget());
@@ -184,7 +151,7 @@ void tst_QWebEngineDownloadItem::clickLink(QPoint linkPos)
QTest::mouseClick(renderWidget, Qt::LeftButton, {}, linkPos);
}
-void tst_QWebEngineDownloadItem::simulateUserAction(QPoint linkPos, UserAction action)
+void tst_QWebEngineDownloadRequest::simulateUserAction(QPoint linkPos, UserAction action)
{
switch (action) {
case SaveLink: return saveLink(linkPos);
@@ -192,17 +159,7 @@ void tst_QWebEngineDownloadItem::simulateUserAction(QPoint linkPos, UserAction a
}
}
-QWebEngineDownloadItem::DownloadType tst_QWebEngineDownloadItem::expectedDownloadType(
- UserAction userAction, const QByteArray &contentDisposition)
-{
- if (userAction == SaveLink)
- return QWebEngineDownloadItem::UserRequested;
- if (contentDisposition == QByteArrayLiteral("attachment"))
- return QWebEngineDownloadItem::Attachment;
- return QWebEngineDownloadItem::DownloadAttribute;
-}
-
-void tst_QWebEngineDownloadItem::downloadLink_data()
+void tst_QWebEngineDownloadRequest::downloadLink_data()
{
QTest::addColumn<UserAction>("userAction");
QTest::addColumn<bool>("anchorHasDownloadAttribute");
@@ -213,7 +170,6 @@ void tst_QWebEngineDownloadItem::downloadLink_data()
QTest::addColumn<QByteArray>("fileDisposition");
QTest::addColumn<bool>("fileHasReferer");
QTest::addColumn<FileAction>("fileAction");
- QTest::addColumn<QWebEngineDownloadItem::DownloadType>("downloadType");
// SaveLink should always trigger a download, even for empty files.
QTest::newRow("save link to empty file")
@@ -221,8 +177,8 @@ void tst_QWebEngineDownloadItem::downloadLink_data()
/* anchorHasDownloadAttribute */ << false
/* fileName */ << QByteArrayLiteral("foo.txt")
/* fileContents */ << QByteArrayLiteral("")
- /* fileMimeTypeDeclared */ << QByteArrayLiteral("")
- /* fileMimeTypeDetected */ << QByteArrayLiteral("")
+ /* fileMimeTypeDeclared */ << QByteArrayLiteral("text/plain")
+ /* fileMimeTypeDetected */ << QByteArrayLiteral("text/plain")
/* fileDisposition */ << QByteArrayLiteral("")
/* fileHasReferer */ << true
/* fileAction */ << FileIsDownloaded;
@@ -308,7 +264,7 @@ void tst_QWebEngineDownloadItem::downloadLink_data()
/* fileMimeTypeDeclared */ << QByteArrayLiteral("text/plain")
/* fileMimeTypeDetected */ << QByteArrayLiteral("text/plain")
/* fileDisposition */ << QByteArrayLiteral("")
- /* fileHasReferer */ << false // crbug.com/455987
+ /* fileHasReferer */ << true
/* fileAction */ << FileIsDownloaded;
// ... same with the content disposition header save for the download type.
@@ -332,7 +288,7 @@ void tst_QWebEngineDownloadItem::downloadLink_data()
/* fileMimeTypeDeclared */ << QByteArrayLiteral("text/plain")
/* fileMimeTypeDetected */ << QByteArrayLiteral("text/plain")
/* fileDisposition */ << QByteArrayLiteral("attachment")
- /* fileHasReferer */ << false // crbug.com/455987
+ /* fileHasReferer */ << true
/* fileAction */ << FileIsDownloaded;
// The file's extension has no effect.
@@ -399,7 +355,7 @@ void tst_QWebEngineDownloadItem::downloadLink_data()
/* fileAction */ << FileIsDownloaded;
}
-void tst_QWebEngineDownloadItem::downloadLink()
+void tst_QWebEngineDownloadRequest::downloadLink()
{
QFETCH(UserAction, userAction);
QFETCH(bool, anchorHasDownloadAttribute);
@@ -440,8 +396,7 @@ void tst_QWebEngineDownloadItem::downloadLink()
rr->setResponseBody(fileContents);
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
@@ -457,31 +412,29 @@ void tst_QWebEngineDownloadItem::downloadLink()
QUrl downloadUrl = m_server->url(slashFileName);
int acceptedCount = 0;
int finishedCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadRequested);
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
QCOMPARE(item->isFinished(), false);
- QCOMPARE(item->totalBytes(), -1);
+ QCOMPARE(item->totalBytes(), fileContents.size());
QCOMPARE(item->receivedBytes(), 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition));
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->isSavePageDownload(), false);
QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected));
QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), suggestedPath);
- QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
+ QCOMPARE(item->savePageFormat(), QWebEngineDownloadRequest::UnknownSaveFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), fileContents.size());
QCOMPARE(item->receivedBytes(), fileContents.size());
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition));
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->isSavePageDownload(), false);
QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected));
QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
- QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
+ QCOMPARE(item->savePageFormat(), QWebEngineDownloadRequest::UnknownSaveFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
@@ -500,7 +453,7 @@ void tst_QWebEngineDownloadItem::downloadLink()
// attribute or not.
QSignalSpy loadSpy(m_page, &QWebEnginePage::loadFinished);
m_view->load(m_server->url());
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
QCOMPARE(indexRequestCount, 1);
@@ -508,7 +461,7 @@ void tst_QWebEngineDownloadItem::downloadLink()
// If file is expected to be displayed and not downloaded then end test
if (fileAction == FileIsDisplayed) {
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
QCOMPARE(acceptedCount, 0);
return;
@@ -527,7 +480,7 @@ void tst_QWebEngineDownloadItem::downloadLink()
QCOMPARE(file.readAll(), fileContents);
}
-void tst_QWebEngineDownloadItem::downloadTwoLinks_data()
+void tst_QWebEngineDownloadRequest::downloadTwoLinks_data()
{
QTest::addColumn<UserAction>("action1");
QTest::addColumn<UserAction>("action2");
@@ -537,7 +490,7 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks_data()
QTest::newRow("Click+Click") << ClickLink << ClickLink;
}
-void tst_QWebEngineDownloadItem::downloadTwoLinks()
+void tst_QWebEngineDownloadRequest::downloadTwoLinks()
{
QFETCH(UserAction, action1);
QFETCH(UserAction, action2);
@@ -561,9 +514,6 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("file2"));
rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
}
});
@@ -573,29 +523,23 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
QString standardDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
int acceptedCount = 0;
int finishedCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadRequested);
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
QCOMPARE(item->isFinished(), false);
- QCOMPARE(item->totalBytes(), -1);
+ QCOMPARE(item->totalBytes(), 5); // strlen("fileN")
QCOMPARE(item->receivedBytes(), 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
+ QCOMPARE(item->savePageFormat(), QWebEngineDownloadRequest::UnknownSaveFormat);
QCOMPARE(item->mimeType(), QStringLiteral("text/plain"));
QString filePart = QChar('/') + item->url().fileName();
QString fileName = item->url().fileName();
QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), standardDir + filePart);
// type() is broken due to race condition in DownloadManagerDelegateQt
- if (action1 == ClickLink && action2 == ClickLink) {
- if (filePart == QStringLiteral("/file1"))
- QCOMPARE(item->type(), expectedDownloadType(action1));
- else if (filePart == QStringLiteral("/file2"))
- QCOMPARE(item->type(), expectedDownloadType(action2, QByteArrayLiteral("attachment")));
- else
+ if (action1 == ClickLink && action2 == ClickLink && filePart != QStringLiteral("/file1") && filePart != QStringLiteral("/file2"))
QFAIL(qPrintable("Unexpected file name: " + filePart));
- }
- connect(item, &QWebEngineDownloadItem::finished, [&]() {
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&]() {
finishedCount++;
});
item->setDownloadDirectory(tmpDir.path());
@@ -607,7 +551,7 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
QSignalSpy loadSpy(m_page, &QWebEnginePage::loadFinished);
m_view->load(m_server->url());
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
// Trigger downloads
@@ -621,20 +565,20 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
QTRY_COMPARE(finishedCount, 2);
}
-void tst_QWebEngineDownloadItem::downloadPage_data()
+void tst_QWebEngineDownloadRequest::downloadPage_data()
{
QTest::addColumn<bool>("saveWithPageAction");
- QTest::addColumn<QWebEngineDownloadItem::SavePageFormat>("savePageFormat");
- QTest::newRow("SingleHtmlSaveFormat") << false << QWebEngineDownloadItem::SingleHtmlSaveFormat;
- QTest::newRow("CompleteHtmlSaveFormat") << false << QWebEngineDownloadItem::CompleteHtmlSaveFormat;
- QTest::newRow("MimeHtmlSaveFormat") << false << QWebEngineDownloadItem::MimeHtmlSaveFormat;
- QTest::newRow("SavePageAction") << true << QWebEngineDownloadItem::MimeHtmlSaveFormat;
+ QTest::addColumn<QWebEngineDownloadRequest::SavePageFormat>("savePageFormat");
+ QTest::newRow("SingleHtmlSaveFormat") << false << QWebEngineDownloadRequest::SingleHtmlSaveFormat;
+ QTest::newRow("CompleteHtmlSaveFormat") << false << QWebEngineDownloadRequest::CompleteHtmlSaveFormat;
+ QTest::newRow("MimeHtmlSaveFormat") << false << QWebEngineDownloadRequest::MimeHtmlSaveFormat;
+ QTest::newRow("SavePageAction") << true << QWebEngineDownloadRequest::MimeHtmlSaveFormat;
}
-void tst_QWebEngineDownloadItem::downloadPage()
+void tst_QWebEngineDownloadRequest::downloadPage()
{
QFETCH(bool, saveWithPageAction);
- QFETCH(QWebEngineDownloadItem::SavePageFormat, savePageFormat);
+ QFETCH(QWebEngineDownloadRequest::SavePageFormat, savePageFormat);
// Set up HTTP server
int indexRequestCount = 0;
@@ -644,9 +588,6 @@ void tst_QWebEngineDownloadItem::downloadPage()
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("text/html"));
rr->setResponseBody(QByteArrayLiteral("<html><body>Hello</body></html>"));
rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
}
});
@@ -657,13 +598,12 @@ void tst_QWebEngineDownloadItem::downloadPage()
QUrl downloadUrl = m_server->url("/");
int acceptedCount = 0;
int finishedCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
- QCOMPARE(item->state(), saveWithPageAction ? QWebEngineDownloadItem::DownloadRequested : QWebEngineDownloadItem::DownloadInProgress);
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
+ QCOMPARE(item->state(), saveWithPageAction ? QWebEngineDownloadRequest::DownloadRequested : QWebEngineDownloadRequest::DownloadInProgress);
QCOMPARE(item->isFinished(), false);
QCOMPARE(item->totalBytes(), -1);
QCOMPARE(item->receivedBytes(), 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->type(), QWebEngineDownloadItem::SavePage);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->isSavePageDownload(), true);
// FIXME(juvaldma): why is mimeType always the same?
QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive"));
@@ -681,13 +621,12 @@ void tst_QWebEngineDownloadItem::downloadPage()
QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), item->receivedBytes());
QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->type(), QWebEngineDownloadItem::SavePage);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->isSavePageDownload(), true);
QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive"));
QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
@@ -704,7 +643,7 @@ void tst_QWebEngineDownloadItem::downloadPage()
// Load some HTML
QSignalSpy loadSpy(m_page, &QWebEnginePage::loadFinished);
m_page->load(m_server->url());
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
QCOMPARE(indexRequestCount, 1);
@@ -720,7 +659,7 @@ void tst_QWebEngineDownloadItem::downloadPage()
QVERIFY(file.exists());
}
-void tst_QWebEngineDownloadItem::downloadViaSetUrl()
+void tst_QWebEngineDownloadRequest::downloadViaSetUrl()
{
// Reproduce the scenario described in QTBUG-63388 by triggering downloads
// of the same file multiple times via QWebEnginePage::setUrl
@@ -735,15 +674,12 @@ void tst_QWebEngineDownloadItem::downloadViaSetUrl()
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("redacted"));
rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
}
});
// Set up profile and download handler
- QVector<QUrl> downloadUrls;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ QList<QUrl> downloadUrls;
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
downloadUrls.append(item->url());
});
@@ -752,8 +688,8 @@ void tst_QWebEngineDownloadItem::downloadViaSetUrl()
QSignalSpy urlSpy(m_page, &QWebEnginePage::urlChanged);
const QUrl indexUrl = m_server->url();
m_page->setUrl(indexUrl);
- QTRY_COMPARE(loadSpy.count(), 1);
- QTRY_COMPARE(urlSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QTRY_COMPARE(urlSpy.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), indexUrl);
@@ -763,9 +699,9 @@ void tst_QWebEngineDownloadItem::downloadViaSetUrl()
for (int i = 0; i != 3; ++i) {
m_page->setUrl(fileUrl);
QCOMPARE(m_page->url(), fileUrl);
- QTRY_COMPARE(loadSpy.count(), 1);
- QTRY_COMPARE(urlSpy.count(), 2);
- QTRY_COMPARE(downloadUrls.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QTRY_COMPARE(urlSpy.size(), 2);
+ QTRY_COMPARE(downloadUrls.size(), 1);
QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), fileUrl);
QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), indexUrl);
@@ -774,20 +710,19 @@ void tst_QWebEngineDownloadItem::downloadViaSetUrl()
}
}
-void tst_QWebEngineDownloadItem::downloadFileNot1()
+void tst_QWebEngineDownloadRequest::downloadFileNot1()
{
// Trigger file download via download() but don't accept().
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
});
- QPointer<QWebEngineDownloadItem> downloadItem;
+ QPointer<QWebEngineDownloadRequest> downloadItem;
int downloadCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
QVERIFY(item);
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadRequested);
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
downloadItem = item;
downloadCount++;
});
@@ -797,20 +732,19 @@ void tst_QWebEngineDownloadItem::downloadFileNot1()
QVERIFY(!downloadItem);
}
-void tst_QWebEngineDownloadItem::downloadFileNot2()
+void tst_QWebEngineDownloadRequest::downloadFileNot2()
{
// Trigger file download via download() but call cancel() instead of accept().
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
});
- QPointer<QWebEngineDownloadItem> downloadItem;
+ QPointer<QWebEngineDownloadRequest> downloadItem;
int downloadCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
QVERIFY(item);
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadRequested);
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
item->cancel();
downloadItem = item;
downloadCount++;
@@ -819,46 +753,44 @@ void tst_QWebEngineDownloadItem::downloadFileNot2()
m_page->download(m_server->url(QByteArrayLiteral("/file")));
QTRY_COMPARE(downloadCount, 1);
QVERIFY(downloadItem);
- QCOMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+ QCOMPARE(downloadItem->state(), QWebEngineDownloadRequest::DownloadCancelled);
}
-void tst_QWebEngineDownloadItem::downloadDeleted()
+void tst_QWebEngineDownloadRequest::downloadDeleted()
{
- QPointer<QWebEngineDownloadItem> downloadItem;
- m_server->setExpectError(true);
- int downloadCount = 0;
- int finishedCount = 0;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ QPointer<QWebEngineDownloadRequest> downloadItem;
+ int downloadCount = 0, finishedCount = 0;
+
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
QVERIFY(item);
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadRequested);
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
downloadItem = item;
- connect(downloadItem, &QWebEngineDownloadItem::finished, [&]() {
- finishedCount++;
- });
+ connect(downloadItem, &QWebEngineDownloadRequest::isFinishedChanged, [&]() { ++finishedCount; });
+ ++downloadCount;
+ // accept and schedule deletion, and check if it still finishes
item->accept();
- downloadCount++;
+ item->deleteLater();
+ QVERIFY(downloadItem);
});
m_page->download(m_server->url(QByteArrayLiteral("/file")));
QTRY_COMPARE(downloadCount, 1);
- QVERIFY(downloadItem);
- QCOMPARE(finishedCount, 0);
- downloadItem->deleteLater();
QTRY_COMPARE(finishedCount, 1);
+ QTRY_VERIFY(!downloadItem);
+ QCOMPARE(downloadCount, 1);
+ QCOMPARE(finishedCount, 1);
}
-void tst_QWebEngineDownloadItem::downloadDeletedByProfile()
+void tst_QWebEngineDownloadRequest::downloadDeletedByProfile()
{
- m_server->setExpectError(true);
-
QPointer<QWebEngineProfile> profile(new QWebEngineProfile);
profile->setHttpCacheType(QWebEngineProfile::NoCache);
profile->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false);
bool downloadFinished = false;
- QPointer<QWebEngineDownloadItem> downloadItem;
- connect(profile, &QWebEngineProfile::downloadRequested, [&] (QWebEngineDownloadItem *item) {
- connect(item, &QWebEngineDownloadItem::finished, [&] () {
+ QPointer<QWebEngineDownloadRequest> downloadItem;
+ connect(profile, &QWebEngineProfile::downloadRequested, [&] (QWebEngineDownloadRequest *item) {
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&] () {
downloadFinished = true;
});
downloadItem = item;
@@ -878,7 +810,7 @@ void tst_QWebEngineDownloadItem::downloadDeletedByProfile()
QTRY_COMPARE(downloadItem.isNull(), true);
}
-void tst_QWebEngineDownloadItem::downloadUniqueFilename_data()
+void tst_QWebEngineDownloadRequest::downloadUniqueFilename_data()
{
QTest::addColumn<QString>("baseName");
QTest::addColumn<QString>("extension");
@@ -887,7 +819,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename_data()
QTest::newRow("tar.gz") << QString("test(1.test)") << QString("tar.gz");
}
-void tst_QWebEngineDownloadItem::downloadUniqueFilename()
+void tst_QWebEngineDownloadRequest::downloadUniqueFilename()
{
QFETCH(QString, baseName);
QFETCH(QString, extension);
@@ -902,28 +834,27 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
// Set up HTTP server
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ auto requestPath = QString::fromUtf8(rr->requestPath());
+ if (rr->requestMethod() == "GET" && requestPath == ("/" + fileName)) {
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("a"));
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
// Set up profile and download handler
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
suggestedFileName = item->suggestedFileName();
item->accept();
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), item->receivedBytes());
QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(item->type(), QWebEngineDownloadItem::Attachment);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->isSavePageDownload(), false);
downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
downloadFinished = true;
@@ -945,7 +876,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
}
}
-void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
+void tst_QWebEngineDownloadRequest::downloadUniqueFilenameWithTimestamp()
{
// Set up HTTP server
QString baseName("test(1.test)");
@@ -960,27 +891,27 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
m_profile->setDownloadPath(tmpDir.path());
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ auto requestPath = QString::fromUtf8(rr->requestPath());
+ if (rr->requestMethod() == "GET" && requestPath == ("/" + fileName)) {
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("a"));
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
// Set up profile and download handler
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
suggestedFileName = item->suggestedFileName();
item->accept();
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), item->receivedBytes());
QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->page(), m_page);
downloadFinished = true;
downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
@@ -1024,7 +955,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
}
}
-void tst_QWebEngineDownloadItem::downloadToDefaultLocation()
+void tst_QWebEngineDownloadRequest::downloadToDefaultLocation()
{
QTemporaryDir tmpDir;
QVERIFY(tmpDir.isValid());
@@ -1041,7 +972,7 @@ void tst_QWebEngineDownloadItem::downloadToDefaultLocation()
QCOMPARE(m_profile->downloadPath(), QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
}
-void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
+void tst_QWebEngineDownloadRequest::downloadToNonExistentDir()
{
QString baseName("test(1.test)");
QString extension("txt");
@@ -1056,27 +987,27 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
// Set up HTTP server
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ auto requestPath = QString::fromUtf8(rr->requestPath());
+ if (rr->requestMethod() == "GET" && requestPath == ("/" + fileName)) {
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("a"));
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
// Set up profile and download handler
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
suggestedFileName = item->suggestedFileName();
item->accept();
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), item->receivedBytes());
QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->page(), m_page);
downloadFinished = true;
downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
@@ -1094,7 +1025,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
QCOMPARE(suggestedFileName, fileName);
}
-void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
+void tst_QWebEngineDownloadRequest::downloadToReadOnlyDir()
{
#ifdef Q_OS_WIN
QSKIP("Cannot change file permissions on Windows.");
@@ -1113,23 +1044,23 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
// Set up HTTP server
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ auto requestPath = QString::fromUtf8(rr->requestPath());
+ if (rr->requestMethod() == "GET" && requestPath == ("/" + fileName)) {
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("a"));
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
- QPointer<QWebEngineDownloadItem> downloadItem;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ QPointer<QWebEngineDownloadRequest> downloadItem;
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
suggestedFileName = item->suggestedFileName();
downloadItem = item;
item->accept();
- connect(item, &QWebEngineDownloadItem::finished, [&]() {
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&]() {
downloadFinished = true;
});
downloadAccepted = true;
@@ -1143,9 +1074,9 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QTRY_VERIFY(downloadAccepted);
QVERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadInterrupted);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadRequest::DownloadInterrupted);
QCOMPARE(downloadItem->isFinished(), false);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::FileAccessDenied);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadRequest::FileAccessDenied);
QVERIFY(!QFile(downloadedFilePath).exists());
QCOMPARE(suggestedFileName, fileName);
@@ -1155,126 +1086,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QFile(m_profile->downloadPath()).setPermissions(QFileDevice::WriteOwner);
}
-#if QT_DEPRECATED_SINCE(5, 14)
-void tst_QWebEngineDownloadItem::downloadPathValidation()
-{
- const QString fileName = "test.txt";
- QString downloadPath;
- QString originalDownloadPath;
-
- QTemporaryDir tmpDir;
- QVERIFY(tmpDir.isValid());
- m_profile->setDownloadPath(tmpDir.path());
-
- // Set up HTTP server
- ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
- rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
- rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
- rr->setResponseBody(QByteArrayLiteral("a"));
- rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
- }
- });
-
- // Set up profile and download handler
- QPointer<QWebEngineDownloadItem> downloadItem;
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
- downloadItem = item;
- originalDownloadPath = item->path();
-
- item->setPath(downloadPath);
- item->accept();
-
- connect(item, &QWebEngineDownloadItem::stateChanged, [&, item](QWebEngineDownloadItem::DownloadState downloadState) {
- if (downloadState == QWebEngineDownloadItem::DownloadInterrupted) {
- item->cancel();
- }
- });
-
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->isFinished(), true);
- QCOMPARE(item->totalBytes(), item->receivedBytes());
- QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->page(), m_page);
- });
- });
-
- QString oldPath = QDir::currentPath();
- QDir::setCurrent(tmpDir.path());
-
- // Set only the file name.
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = fileName;
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), fileName);
-
- // Set only the directory path.
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = tmpDir.path();
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), originalDownloadPath);
-
- // Set only the directory path with separator.
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = tmpDir.path() + QDir::separator();
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), originalDownloadPath);
-
- // Set only the directory with the current directory path without ending separator.
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = ".";
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), originalDownloadPath);
-
- // Set only the directory with the current directory path with ending separator.
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = "./";
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), originalDownloadPath);
-
- downloadItem.clear();
- originalDownloadPath = "";
- downloadPath = "...";
- m_page->setUrl(m_server->url("/" + fileName));
- QTRY_VERIFY(downloadItem);
-#if !defined(Q_OS_WIN)
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::FileFailed);
- QCOMPARE(downloadItem->path(), downloadPath);
-#else
- // Windows interprets the "..." path as a valid path. It will be the current path.
- QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
- QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
- QCOMPARE(downloadItem->path(), originalDownloadPath);
-#endif // !defined(Q_OS_WIN)
- QDir::setCurrent(oldPath);
-}
-#endif
-
-void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName_data()
+void tst_QWebEngineDownloadRequest::downloadToDirectoryWithFileName_data()
{
QTest::addColumn<bool>("setDirectoryFirst");
@@ -1282,7 +1094,7 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName_data()
QTest::newRow("setFileNameFirst") << false;
}
-void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
+void tst_QWebEngineDownloadRequest::downloadToDirectoryWithFileName()
{
QFETCH(bool, setDirectoryFirst);
QString downloadDirectory;
@@ -1300,44 +1112,51 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
// Set up HTTP server
ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
- if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ auto requestPath = QString::fromUtf8(rr->requestPath());
+ if (rr->requestMethod() == "GET" && requestPath == ("/" + fileName)) {
rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
rr->setResponseBody(QByteArrayLiteral("a"));
rr->sendResponse();
} else {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ rr->sendResponse(404);
}
});
// Set up profile and download handler
- ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
-
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
+ QSignalSpy fileNameSpy(item, &QWebEngineDownloadRequest::downloadFileNameChanged);
+ QSignalSpy directorySpy(item, &QWebEngineDownloadRequest::downloadDirectoryChanged);
+ bool isUniquifiedFileName = false;
if (!downloadDirectory.isEmpty() && setDirectoryFirst) {
+ const QString &originalFileName = item->downloadFileName();
item->setDownloadDirectory(downloadDirectory);
QCOMPARE(item->downloadDirectory(), downloadDirectory);
+ QCOMPARE(directorySpy.size(), 1);
+ isUniquifiedFileName = (originalFileName != item->downloadFileName());
+ QCOMPARE(fileNameSpy.size(), isUniquifiedFileName ? 1 : 0);
}
if (!downloadFileName.isEmpty()) {
item->setDownloadFileName(downloadFileName);
QCOMPARE(item->downloadFileName(), downloadFileName);
+ QCOMPARE(fileNameSpy.size(), isUniquifiedFileName ? 2 : 1);
}
if (!downloadDirectory.isEmpty() && !setDirectoryFirst) {
item->setDownloadDirectory(downloadDirectory);
QCOMPARE(item->downloadDirectory(), downloadDirectory);
+ QCOMPARE(directorySpy.size(), 1);
}
- QCOMPARE(item->path(), QDir(item->downloadDirectory()).filePath(item->downloadFileName()));
item->accept();
- connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
- QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadCompleted);
QCOMPARE(item->isFinished(), true);
QCOMPARE(item->totalBytes(), item->receivedBytes());
QVERIFY(item->receivedBytes() > 0);
- QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadRequest::NoReason);
QCOMPARE(item->page(), m_page);
downloadFinished = true;
downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
@@ -1375,7 +1194,7 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
QCOMPARE(downloadedSuggestedFileName, fileName);
// Download another file to the same directory and set file name by
- // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
+ // QWebEngineDownloadRequest::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
downloadFinished = false;
downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator();
downloadFileName = "test1.txt";
@@ -1396,7 +1215,7 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
QCOMPARE(downloadedSuggestedFileName, fileName);
// Download the same file to same directory and set file name by
- // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
+ // QWebEngineDownloadRequest::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
downloadFinished = false;
downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator();
downloadFileName = "test1.txt";
@@ -1418,5 +1237,50 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
QCOMPARE(downloadedSuggestedFileName, fileName);
}
-QTEST_MAIN(tst_QWebEngineDownloadItem)
-#include "tst_qwebenginedownloaditem.moc"
+void tst_QWebEngineDownloadRequest::downloadDataUrls_data()
+{
+ QTest::addColumn<QByteArray>("htmlData");
+ QTest::addColumn<QString>("expectedFileName");
+ QTest::newRow("data url without slash") << QByteArrayLiteral("<html><head><meta charset=\"utf-8\"></head><body><a href=\"data:application/gzip;base64,dGVzdA==\">data URL without slash</a><br/></body></html>") << QStringLiteral("qwe_download.gz") ;
+ QTest::newRow("data url with slash") << QByteArrayLiteral("<html><head><meta charset=\"utf-8\"></head><body><a href=\"data:application/gzip;base64,dGVzcnI/dGVzdA==\">data URL with filename</a><br/></body></html>") << QStringLiteral("qwe_download.gz") ;
+ QTest::newRow("data url with download tag") << QByteArrayLiteral("<html><head><meta charset=\"utf-8\"></head><body><a href=\"data:application/gzip;base64,dGVzdA/IHRlc3Q=\" download=\"filename.gz\">data URL with filename</a><br/></body></html>") << QStringLiteral("filename.gz") ;
+
+}
+
+void tst_QWebEngineDownloadRequest::downloadDataUrls()
+{
+ QFETCH(QByteArray, htmlData);
+ QFETCH(QString, expectedFileName);
+ // Set up HTTP server
+ ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
+ if (rr->requestMethod() == "GET" && rr->requestPath() == "/") {
+ rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("text/html"));
+ rr->setResponseBody(htmlData);
+ rr->sendResponse();
+ }
+ });
+
+ // Set up profile and download handler
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+ m_profile->setDownloadPath(tmpDir.path());
+
+ int downloadRequestCount = 0;
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadRequest *item) {
+ QCOMPARE(item->state(), QWebEngineDownloadRequest::DownloadRequested);
+ QCOMPARE(item->downloadFileName(), expectedFileName);
+ downloadRequestCount++;
+ });
+
+ QSignalSpy loadSpy(m_page, &QWebEnginePage::loadFinished);
+ m_view->load(m_server->url());
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
+
+ // Trigger download
+ simulateUserAction(QPoint(10, 10), UserAction::ClickLink);
+ QTRY_COMPARE(downloadRequestCount, 1);
+}
+
+QTEST_MAIN(tst_QWebEngineDownloadRequest)
+#include "tst_qwebenginedownloadrequest.moc"
diff --git a/tests/auto/widgets/qwebenginehistory/CMakeLists.txt b/tests/auto/widgets/qwebenginehistory/CMakeLists.txt
new file mode 100644
index 000000000..e277a7326
--- /dev/null
+++ b/tests/auto/widgets/qwebenginehistory/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebenginehistory
+ SOURCES
+ tst_qwebenginehistory.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+set(tst_qwebenginehistory_resource_files
+ "resources/page1.html"
+ "resources/page2.html"
+ "resources/page3.html"
+ "resources/page4.html"
+ "resources/page5.html"
+ "resources/page6.html"
+)
+
+qt_internal_add_resource(tst_qwebenginehistory "tst_qwebenginehistory"
+ PREFIX
+ "/"
+ FILES
+ ${tst_qwebenginehistory_resource_files}
+)
+
diff --git a/tests/auto/widgets/qwebenginehistory/qwebenginehistory.pro b/tests/auto/widgets/qwebenginehistory/qwebenginehistory.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/qwebenginehistory/qwebenginehistory.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
index bdb486793..ad66e972c 100644
--- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
+++ b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
@@ -20,7 +20,7 @@
#include <QtTest/QtTest>
#include <QAction>
-#include "../util.h"
+#include <util.h>
#include "qwebenginepage.h"
#include "qwebengineview.h"
#include "qwebenginehistory.h"
@@ -39,7 +39,7 @@ protected :
{
loadFinishedSpy->clear();
page->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html"));
- QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ QTRY_COMPARE(loadFinishedSpy->size(), 1);
loadFinishedSpy->clear();
}
@@ -150,8 +150,8 @@ void tst_QWebEngineHistory::back()
for (int i = histsize;i > 1;i--) {
QTRY_COMPARE(toPlainTextSync(page), QString("page") + QString::number(i));
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), histsize-i+1);
- QTRY_COMPARE(titleChangedSpy.count(), histsize-i+1);
+ QTRY_COMPARE(loadFinishedSpy->size(), histsize-i+1);
+ QTRY_COMPARE(titleChangedSpy.size(), histsize-i+1);
}
//try one more time (too many). crash test
hist->back();
@@ -168,15 +168,15 @@ void tst_QWebEngineHistory::forward()
while (hist->canGoBack()) {
hist->back();
histBackCount++;
- QTRY_COMPARE(loadFinishedSpy->count(), histBackCount);
+ QTRY_COMPARE(loadFinishedSpy->size(), histBackCount);
}
QSignalSpy titleChangedSpy(page, SIGNAL(titleChanged(const QString&)));
for (int i = 1;i < histsize;i++) {
QTRY_COMPARE(toPlainTextSync(page), QString("page") + QString::number(i));
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), i+histBackCount);
- QTRY_COMPARE(titleChangedSpy.count(), i);
+ QTRY_COMPARE(loadFinishedSpy->size(), i+histBackCount);
+ QTRY_COMPARE(titleChangedSpy.size(), i);
}
//try one more time (too many). crash test
hist->forward();
@@ -205,15 +205,15 @@ void tst_QWebEngineHistory::goToItem()
QWebEngineHistoryItem current = hist->currentItem();
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ QTRY_COMPARE(loadFinishedSpy->size(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->size(), 2);
QVERIFY(hist->currentItem().title() != current.title());
hist->goToItem(current);
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->size(), 2);
QTRY_COMPARE(hist->currentItem().title(), current.title());
}
@@ -225,7 +225,7 @@ void tst_QWebEngineHistory::items()
{
QList<QWebEngineHistoryItem> items = hist->items();
//check count
- QTRY_COMPARE(histsize, items.count());
+ QTRY_COMPARE(histsize, items.size());
//check order
for (int i = 1;i <= histsize;i++) {
@@ -236,10 +236,10 @@ void tst_QWebEngineHistory::items()
void tst_QWebEngineHistory::backForwardItems()
{
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ QTRY_COMPARE(loadFinishedSpy->size(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->size(), 2);
QTRY_COMPARE(hist->items().size(), 5);
QTRY_COMPARE(hist->backItems(100).size(), 2);
@@ -297,9 +297,9 @@ void tst_QWebEngineHistory::serialize_2()
hist->back();
QTRY_VERIFY(evaluateJavaScriptSync(page, "location.hash").toString().isEmpty());
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ QTRY_COMPARE(loadFinishedSpy->size(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->size(), 2);
//check if current index was changed (make sure that it is not last item)
QVERIFY(hist->currentItemIndex() != initialCurrentIndex);
//save current index
@@ -310,17 +310,18 @@ void tst_QWebEngineHistory::serialize_2()
load >> *hist;
QVERIFY(load.status() == QDataStream::Ok);
// Restoring the history will trigger a load.
- QTRY_COMPARE(loadFinishedSpy->count(), 3);
+ QTRY_COMPARE(loadFinishedSpy->size(), 3);
//check current index
QTRY_COMPARE(hist->currentItemIndex(), oldCurrentIndex);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 4);
+ QTRY_COMPARE(loadFinishedSpy->size(), 4);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 5);
+ QTRY_COMPARE(loadFinishedSpy->size(), 5);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 6);
+ // In-page navigation, the last url was the page5.html
+ QTRY_COMPARE(loadFinishedSpy->size(), 5);
QTRY_COMPARE(hist->currentItemIndex(), initialCurrentIndex);
}
@@ -428,7 +429,7 @@ void tst_QWebEngineHistory::saveAndRestore_crash_4()
QSignalSpy loadFinishedSpy2(page2.data(), SIGNAL(loadFinished(bool)));
QDataStream load(&buffer, QIODevice::ReadOnly);
load >> *page2->history();
- QTRY_COMPARE(loadFinishedSpy2.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy2.size(), 1);
}
void tst_QWebEngineHistory::saveAndRestore_InternalPage()
@@ -467,7 +468,7 @@ void tst_QWebEngineHistory::popPushState()
QWebEnginePage page;
QSignalSpy spyLoadFinished(&page, SIGNAL(loadFinished(bool)));
page.setHtml("<html><body>long live Qt!</body></html>");
- QTRY_COMPARE(spyLoadFinished.count(), 1);
+ QTRY_COMPARE(spyLoadFinished.size(), 1);
evaluateJavaScriptSync(&page, script);
}
@@ -486,9 +487,9 @@ void tst_QWebEngineHistory::clear()
QWebEnginePage page2(this);
QWebEngineHistory* hist2 = page2.history();
- QVERIFY(hist2->count() == 0);
+ QCOMPARE(hist2->count(), 0);
hist2->clear();
- QVERIFY(hist2->count() == 0); // Do not change anything.
+ QCOMPARE(hist2->count(), 0); // Do not change anything.
}
void tst_QWebEngineHistory::historyItemFromDeletedPage()
diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.qrc b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.qrc
deleted file mode 100644
index cdfe575a0..000000000
--- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.qrc
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/page1.html</file>
- <file>resources/page2.html</file>
- <file>resources/page3.html</file>
- <file>resources/page4.html</file>
- <file>resources/page5.html</file>
- <file>resources/page6.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST
index 02b297d5a..52def48d1 100644
--- a/tests/auto/widgets/qwebenginepage/BLACKLIST
+++ b/tests/auto/widgets/qwebenginepage/BLACKLIST
@@ -5,8 +5,11 @@ osx
windows
macos # Can't move cursor (QTBUG-76312)
-[devTools]
-msvc-2019
+[comboBoxPopupPositionAfterMove]
+macos
-[setLifecycleStateWithDevTools]
-msvc-2019
+[comboBoxPopupPositionAfterChildMove]
+macos
+
+[backgroundColor]
+macos
diff --git a/tests/auto/widgets/qwebenginepage/CMakeLists.txt b/tests/auto/widgets/qwebenginepage/CMakeLists.txt
new file mode 100644
index 000000000..f63d6211c
--- /dev/null
+++ b/tests/auto/widgets/qwebenginepage/CMakeLists.txt
@@ -0,0 +1,68 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebenginepage
+ SOURCES
+ tst_qwebenginepage.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::NetworkPrivate
+ Qt::WebEngineCorePrivate
+ Qt::WebEngineWidgets
+ Test::HttpServer
+ Test::Util
+)
+
+get_target_property(sharedData Test::HttpServer SHARED_DATA)
+
+set(tst_qwebenginepage_resource_files
+ "resources/redirect.html"
+ "resources/bar.txt"
+ "resources/content.html"
+ "resources/dynamicFrame.html"
+ "resources/foo.txt"
+ "resources/fontaccess.html"
+ "resources/frame_a.html"
+ "resources/frame_c.html"
+ "resources/framedindex.html"
+ "resources/fullscreen.html"
+ "resources/iframe.html"
+ "resources/iframe2.html"
+ "resources/iframe3.html"
+ "resources/image.png"
+ "resources/index.html"
+ "resources/lifecycle.html"
+ "resources/pasteimage.html"
+ "resources/path with spaces.txt"
+ "resources/reload.html"
+ "resources/script.html"
+ "resources/style.css"
+ "resources/test1.html"
+ "resources/test2.html"
+ "resources/testiframe.html"
+ "resources/testiframe2.html"
+ "resources/user.css"
+)
+
+qt_internal_add_resource(tst_qwebenginepage "tst_qwebenginepage"
+ PREFIX
+ "/"
+ FILES
+ ${tst_qwebenginepage_resource_files}
+)
+set_source_files_properties("${sharedData}/notification.html"
+ PROPERTIES QT_RESOURCE_ALIAS "notification.html"
+)
+set(tst_qwebenginepage1_resource_files
+ "${sharedData}/notification.html"
+)
+
+qt_internal_add_resource(tst_qwebenginepage "tst_qwebenginepage1"
+ PREFIX
+ "/shared"
+ FILES
+ ${tst_qwebenginepage1_resource_files}
+)
diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
deleted file mode 100644
index 18a66c466..000000000
--- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-include(../tests.pri)
-include(../../shared/http.pri)
-QT *= core-private
diff --git a/tests/auto/widgets/qwebenginepage/resources/fontaccess.html b/tests/auto/widgets/qwebenginepage/resources/fontaccess.html
new file mode 100644
index 000000000..1a0fe8af9
--- /dev/null
+++ b/tests/auto/widgets/qwebenginepage/resources/fontaccess.html
@@ -0,0 +1,14 @@
+<html>
+<body onkeypress='onKeyPress()'>
+<a>This is test content</a>
+<script>
+var done = false;
+var fonts;
+var activated = false;
+function onKeyPress() {
+ activated = true;
+ window.queryLocalFonts().then(f => { fonts = f; done = true; });
+}
+</script>
+</body>
+</html>
diff --git a/tests/auto/widgets/resources/image2.png b/tests/auto/widgets/qwebenginepage/resources/image2.png
index 8d703640c..8d703640c 100644
--- a/tests/auto/widgets/resources/image2.png
+++ b/tests/auto/widgets/qwebenginepage/resources/image2.png
Binary files differ
diff --git a/tests/auto/widgets/qwebenginepage/resources/redirect.html b/tests/auto/widgets/qwebenginepage/resources/redirect.html
new file mode 100644
index 000000000..db06d73a7
--- /dev/null
+++ b/tests/auto/widgets/qwebenginepage/resources/redirect.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<script>
+function doRedirect() { location.replace('qrc:///resources/content.html') }
+document.addEventListener("DOMContentLoaded", doRedirect)
+</script>
+</body>
+</html>
diff --git a/tests/auto/widgets/qwebenginepage/resources/reload.html b/tests/auto/widgets/qwebenginepage/resources/reload.html
index d9c33dfcd..062d06807 100644
--- a/tests/auto/widgets/qwebenginepage/resources/reload.html
+++ b/tests/auto/widgets/qwebenginepage/resources/reload.html
@@ -1,6 +1,6 @@
<html>
<head>
-<meta http-equiv="refresh" content="2">
+<meta http-equiv="refresh" content="2;url=qrc:///resources/content.html">
</head>
<body>
This is test content
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 621c2dbd7..f1d64776b 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
@@ -19,8 +19,10 @@
Boston, MA 02110-1301, USA.
*/
-#include "../util.h"
+#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>
@@ -31,11 +33,13 @@
#include <QMenu>
#include <QMimeDatabase>
#include <QNetworkProxy>
-#include <QOpenGLWidget>
#include <QPaintEngine>
#include <QPushButton>
#include <QScreen>
-#include <QStateMachine>
+#include <QWheelEvent>
+#if defined(QT_STATEMACHINE_LIB)
+# include <QStateMachine>
+#endif
#include <QtGui/QClipboard>
#include <QtTest/QtTest>
#include <QTextCharFormat>
@@ -46,10 +50,15 @@
#include <qnetworkcookiejar.h>
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
-#include <qwebenginedownloaditem.h>
+#include <qwebengineclienthints.h>
+#include <qwebenginedownloadrequest.h>
+#include <qwebenginedesktopmediarequest.h>
+#include <qwebenginefilesystemaccessrequest.h>
#include <qwebenginefindtextresult.h>
#include <qwebenginefullscreenrequest.h>
#include <qwebenginehistory.h>
+#include <qwebenginenavigationrequest.h>
+#include <qwebenginenewwindowrequest.h>
#include <qwebenginenotification.h>
#include <qwebenginepage.h>
#include <qwebengineprofile.h>
@@ -58,14 +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
@@ -73,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
@@ -89,12 +112,18 @@ public Q_SLOTS:
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
+ void comboBoxPopupPositionAfterMove_data();
void comboBoxPopupPositionAfterMove();
+ void comboBoxPopupPositionAfterChildMove_data();
void comboBoxPopupPositionAfterChildMove();
void acceptNavigationRequest();
+ void acceptNavigationRequestWithFormData();
void acceptNavigationRequestNavigationType();
+ void acceptNavigationRequestRelativeToNothing();
+#ifndef Q_OS_MACOS
void geolocationRequestJS_data();
void geolocationRequestJS();
+#endif
void loadFinished();
void actionStates();
void pasteImage();
@@ -129,11 +158,13 @@ private Q_SLOTS:
void findTextCalledOnMatch();
void findTextActiveMatchOrdinal();
void deleteQWebEngineViewTwice();
+#if defined(QT_STATEMACHINE_LIB)
void loadSignalsOrder_data();
void loadSignalsOrder();
+#endif
void openWindowDefaultSize();
-#ifdef Q_OS_MAC
+#ifdef Q_OS_MACOS
void macCopyUnicodeToClipboard();
#endif
@@ -141,7 +172,8 @@ private Q_SLOTS:
void runJavaScriptDisabled();
void runJavaScriptFromSlot();
void fullScreenRequested();
- void quotaRequested();
+ void requestQuota_data();
+ void requestQuota();
// Tests from tst_QWebEngineFrame
@@ -173,7 +205,6 @@ private Q_SLOTS:
void setUrlUsingStateObject();
void setUrlThenLoads_data();
void setUrlThenLoads();
- void loadFinishedAfterNotFoundError();
void loadInSignalHandlers_data();
void loadInSignalHandlers();
void loadFromQrc();
@@ -204,7 +235,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();
@@ -225,6 +262,8 @@ private Q_SLOTS:
void editActionsWithoutSelection();
void customUserAgentInNewTab();
+ void openNewTabInDifferentProfile_data();
+ void openNewTabInDifferentProfile();
void renderProcessCrashed();
void renderProcessPid();
void backgroundColor();
@@ -233,20 +272,54 @@ private Q_SLOTS:
void isSafeRedirect_data();
void isSafeRedirect();
+ void testChooseFilesParameters_data();
+ 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()
@@ -288,6 +361,18 @@ void tst_QWebEnginePage::initTestCase()
#endif
searchPath += QStringLiteral("/../../../plugins");
QCoreApplication::addLibraryPath(searchPath);
+
+ 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()
@@ -295,6 +380,23 @@ void tst_QWebEnginePage::cleanupTestCase()
cleanupFiles(); // Be nice
}
+class EchoingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
+{
+public:
+ EchoingUrlSchemeHandler(QObject *parent = nullptr)
+ : QWebEngineUrlSchemeHandler(parent)
+ {
+ }
+ ~EchoingUrlSchemeHandler() = default;
+
+ void requestStarted(QWebEngineUrlRequestJob *job) override
+ {
+ QBuffer *buffer = new QBuffer(job);
+ buffer->setData(job->requestUrl().toString(QUrl::RemoveScheme).toUtf8());
+ job->reply("text/plain;charset=utf-8", buffer);
+ }
+};
+
class NavigationRequestOverride : public QWebEnginePage
{
public:
@@ -302,7 +404,7 @@ public:
bool m_acceptNavigationRequest;
protected:
- virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
+ bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override
{
Q_UNUSED(url);
Q_UNUSED(isMainFrame);
@@ -315,24 +417,26 @@ protected:
void tst_QWebEnginePage::acceptNavigationRequest()
{
QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile));
NavigationRequestOverride page(&profile, false);
QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
- page.setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
- "<input type='text'><input type='submit'></form></body></html>"), QUrl());
- QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000);
+ 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.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?"));
+ QCOMPARE(toPlainTextSync(&page), QString("/foo?"));
}
class JSTestPage : public QWebEnginePage
@@ -365,6 +469,7 @@ private:
bool m_allowGeolocation;
};
+#ifndef Q_OS_MACOS
void tst_QWebEnginePage::geolocationRequestJS_data()
{
QTest::addColumn<bool>("allowed");
@@ -379,7 +484,7 @@ void tst_QWebEnginePage::geolocationRequestJS()
QFETCH(int, errorCode);
QWebEngineView view;
JSTestPage *newPage = new JSTestPage(&view);
- newPage->setView(&view);
+ view.setPage(newPage);
newPage->setGeolocationPermission(allowed);
connect(newPage, SIGNAL(featurePermissionRequested(const QUrl&, QWebEnginePage::Feature)),
@@ -387,7 +492,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();
@@ -404,6 +509,7 @@ void tst_QWebEnginePage::geolocationRequestJS()
QEXPECT_FAIL("", "No location service available.", Continue);
QCOMPARE(result, errorCode);
}
+#endif
void tst_QWebEnginePage::loadFinished()
{
@@ -414,19 +520,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()
@@ -483,6 +589,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);
@@ -493,7 +600,7 @@ class ConsolePage : public QWebEnginePage
public:
ConsolePage(QObject* parent = 0) : QWebEnginePage(parent) {}
- virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID)
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override
{
levels.append(level);
messages.append(message);
@@ -512,42 +619,29 @@ 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);
}
class TestPage : public QWebEnginePage {
Q_OBJECT
public:
- TestPage(QObject* parent = 0) : QWebEnginePage(parent)
+ TestPage(QObject *parent = nullptr, QWebEngineProfile *profile = nullptr) : QWebEnginePage(profile, parent)
{
- connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect)));
+ connect(this, &QWebEnginePage::geometryChangeRequested, this, &TestPage::slotGeometryChangeRequested);
+ connect(this, &QWebEnginePage::navigationRequested, this, &TestPage::slotNavigationRequested);
+ connect(this, &QWebEnginePage::newWindowRequested, this, &TestPage::slotNewWindowRequested);
}
struct Navigation {
- NavigationType type;
+ QWebEngineNavigationRequest::NavigationType type;
QUrl url;
bool isMainFrame;
+ bool hasFormData;
};
QList<Navigation> navigations;
- virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
- {
- Navigation n;
- n.url = url;
- n.type = type;
- n.isMainFrame = isMainFrame;
- navigations.append(n);
- return true;
- }
-
QList<TestPage*> createdWindows;
- virtual QWebEnginePage* createWindow(WebWindowType) {
- TestPage* page = new TestPage(this);
- createdWindows.append(page);
- emit windowCreated();
- return page;
- }
QRect requestedGeometry;
@@ -555,77 +649,182 @@ signals:
void windowCreated();
private Q_SLOTS:
- void slotGeometryChangeRequested(const QRect& geom) {
+ void slotNavigationRequested(QWebEngineNavigationRequest &request)
+ {
+ Navigation n;
+ n.url = request.url();
+ n.type = request.navigationType();
+ n.isMainFrame = request.isMainFrame();
+ n.hasFormData = request.hasFormData();
+ navigations.append(n);
+ request.accept();
+ }
+ void slotNewWindowRequested(QWebEngineNewWindowRequest &request)
+ {
+ TestPage *page = new TestPage(this, profile());
+ createdWindows.append(page);
+ emit windowCreated();
+ request.openIn(page);
+ }
+
+ void slotGeometryChangeRequested(const QRect &geom)
+ {
requestedGeometry = geom;
}
};
-void tst_QWebEnginePage::acceptNavigationRequestNavigationType()
+void tst_QWebEnginePage::acceptNavigationRequestWithFormData()
{
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile));
+ TestPage page(nullptr, &profile);
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+
+ page.setHtml(QString("<html><body><form name='tstform' action='foo' method='post'>"
+ "<input type='text'><input type='submit'></form></body></html>"),
+ QUrl("echo:/"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);
+ QCOMPARE(page.navigations[0].type, QWebEngineNavigationRequest::TypedNavigation);
+ QVERIFY(!page.navigations[0].hasFormData);
+ evaluateJavaScriptSync(&page, "tstform.submit();");
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QCOMPARE(page.navigations[1].type, QWebEngineNavigationRequest::FormSubmittedNavigation);
+ QVERIFY(page.navigations[1].hasFormData);
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(loadSpy.size(), 3);
+ QCOMPARE(page.navigations[2].type, QWebEngineNavigationRequest::ReloadNavigation);
+ QVERIFY(page.navigations[2].hasFormData);
+}
+
+void tst_QWebEnginePage::acceptNavigationRequestNavigationType()
+{
TestPage page;
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);
+ QTRY_COMPARE(loadSpy.size(), 4);
+ QTRY_COMPARE(page.navigations.size(), 4);
+ QList<QWebEngineNavigationRequest::NavigationType> expectedList;
+ expectedList << QWebEngineNavigationRequest::TypedNavigation
+ << QWebEngineNavigationRequest::TypedNavigation
+ << QWebEngineNavigationRequest::BackForwardNavigation
+ << QWebEngineNavigationRequest::ReloadNavigation;
+
+ // client side redirect
page.load(QUrl("qrc:///resources/reload.html"));
- QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 6, 20000);
- QTRY_COMPARE(page.navigations.count(), 6);
-
- QList<QWebEnginePage::NavigationType> expectedList;
- expectedList << QWebEnginePage::NavigationTypeTyped
- << QWebEnginePage::NavigationTypeTyped
- << QWebEnginePage::NavigationTypeBackForward
- << QWebEnginePage::NavigationTypeReload
- << QWebEnginePage::NavigationTypeTyped
- << QWebEnginePage::NavigationTypeRedirect;
- QVERIFY(expectedList.count() == page.navigations.count());
- for (int i = 0; i < expectedList.count(); ++i) {
+ 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.size(), 7, 20000);
+ QTRY_COMPARE(page.navigations.size(), 8);
+ expectedList += { QWebEngineNavigationRequest::TypedNavigation, QWebEngineNavigationRequest::RedirectNavigation };
+
+ // server side redirect
+ HttpServer server;
+ server.setResourceDirs({ ":/resources" });
+ connect(&server, &HttpServer::newRequest, &server, [&] (HttpReqRep *r) {
+ if (r->requestMethod() == "GET") {
+ if (r->requestPath() == "/redirect1.html") {
+ r->setResponseHeader("Location", server.url("/redirect2.html").toEncoded());
+ r->setResponseBody("<html><body>Redirect1</body></html>");
+ r->sendResponse(307); // Internal server redirect
+ } else if (r->requestPath() == "/redirect2.html") {
+ r->setResponseHeader("Location", server.url("/content.html").toEncoded());
+ r->setResponseBody("<html><body>Redirect2</body></html>");
+ r->sendResponse(301); // Moved permanently
+ }
+ }
+ });
+ QVERIFY(server.start());
+ page.load(QUrl(server.url("/redirect1.html")));
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 8, 20000);
+ expectedList += {
+ QWebEngineNavigationRequest::TypedNavigation,
+ QWebEngineNavigationRequest::RedirectNavigation,
+ QWebEngineNavigationRequest::RedirectNavigation
+ };
+
+ for (int i = 0; i < expectedList.size(); ++i) {
+ QTRY_VERIFY(i < page.navigations.size());
QCOMPARE(page.navigations[i].type, expectedList[i]);
}
+ QVERIFY(expectedList.size() == page.navigations.size());
}
-void tst_QWebEnginePage::popupFormSubmission()
+// Relative url without base url.
+//
+// See also: QTBUG-48435
+void tst_QWebEnginePage::acceptNavigationRequestRelativeToNothing()
{
TestPage page;
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+
+ page.setHtml(QString("<html><body><a id='link' href='S0'>limited time offer</a></body></html>"),
+ /* baseUrl: */ QUrl());
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);
+ page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()"));
+ 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.size(), 3, 20000);
+ page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()"));
+ 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.size(), 3);
+ QCOMPARE(page.navigations[0].type, QWebEngineNavigationRequest::TypedNavigation);
+ QCOMPARE(page.navigations[1].type, QWebEngineNavigationRequest::TypedNavigation);
+ QCOMPARE(page.navigations[2].type, QWebEngineNavigationRequest::LinkClickedNavigation);
+ QCOMPARE(page.navigations[2].url, QUrl(QString("qrc:/S0")));
+}
+
+void tst_QWebEnginePage::popupFormSubmission()
+{
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile));
+ TestPage page(nullptr, &profile);
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
QSignalSpy windowCreatedSpy(&page, SIGNAL(windowCreated()));
page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
page.setHtml("<form name='form1' method=get action='' target='myNewWin'>"
" <input type='hidden' name='foo' value='bar'>"
- "</form>");
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 20000);
+ "</form>", QUrl("echo:"));
+ 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
@@ -637,7 +836,8 @@ public:
QList<QNetworkRequest> requests;
protected:
- virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
+ QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) override
+ {
requests.append(request);
requestedUrls.append(request.url());
return QNetworkAccessManager::createRequest(op, request, outgoingData);
@@ -665,16 +865,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"));
@@ -723,7 +923,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);
@@ -750,7 +950,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());
@@ -771,7 +971,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) {
@@ -783,7 +983,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();
}
@@ -810,8 +1010,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());
@@ -824,13 +1024,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());
}
@@ -904,7 +1105,7 @@ public:
JSPromptPage()
{}
- bool javaScriptPrompt(const QUrl &securityOrigin, const QString& msg, const QString& defaultValue, QString* result)
+ bool javaScriptPrompt(const QUrl &securityOrigin, const QString& msg, const QString& defaultValue, QString* result) override
{
if (msg == QLatin1String("test1")) {
*result = QString();
@@ -931,7 +1132,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,
@@ -965,7 +1166,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());
@@ -975,22 +1176,22 @@ void tst_QWebEnginePage::findText()
// Invoking a stopFinding operation will not change or clear the currently selected text,
// if nothing was found beforehand.
{
- CallbackSpy<bool> callbackSpy;
+ CallbackSpy<QWebEngineFindTextResult> callbackSpy;
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"));
}
// Invoking a startFinding operation with text that won't be found, will clear the current
// selection.
{
- CallbackSpy<bool> callbackSpy;
+ CallbackSpy<QWebEngineFindTextResult> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
m_view->findText("Will not be found", {}, callbackSpy.ref());
- QCOMPARE(callbackSpy.waitForResult(), false);
- QTRY_COMPARE(signalSpy.count(), 1);
+ QCOMPARE(callbackSpy.waitForResult().numberOfMatches(), 0);
+ QTRY_COMPARE(signalSpy.size(), 1);
auto result = signalSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
QCOMPARE(result.numberOfMatches(), 0);
QTRY_VERIFY(m_view->selectedText().isEmpty());
@@ -1003,22 +1204,22 @@ void tst_QWebEnginePage::findText()
// Invoking a startFinding operation with text that will be found, will clear the current
// selection as well.
{
- CallbackSpy<bool> callbackSpy;
+ CallbackSpy<QWebEngineFindTextResult> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
m_view->findText("foo", {}, callbackSpy.ref());
- QVERIFY(callbackSpy.waitForResult());
- QTRY_COMPARE(signalSpy.count(), 1);
+ QVERIFY(callbackSpy.waitForResult().numberOfMatches() > 0);
+ QTRY_COMPARE(signalSpy.size(), 1);
QTRY_VERIFY(m_view->selectedText().isEmpty());
}
// Invoking a stopFinding operation after text was found, will set the selected text to the
// found text.
{
- CallbackSpy<bool> callbackSpy;
+ CallbackSpy<QWebEngineFindTextResult> callbackSpy;
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"));
}
@@ -1028,7 +1229,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);
@@ -1039,11 +1240,11 @@ void tst_QWebEnginePage::findText()
void tst_QWebEnginePage::findTextResult()
{
QSignalSpy findTextSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- auto signalResult = [&findTextSpy]() -> QVector<int> {
- if (findTextSpy.count() != 1)
- return QVector<int>({-1, -1});
+ auto signalResult = [&findTextSpy]() -> QList<int> {
+ if (findTextSpy.size() != 1)
+ return QList<int>({-1, -1});
auto r = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
- return QVector<int>({ r.numberOfMatches(), r.activeMatch() });
+ return QList<int>({ r.numberOfMatches(), r.activeMatch() });
};
// findText will abort in blink if the view has an empty size.
@@ -1052,36 +1253,36 @@ 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(), QVector<int>({0, 0}));
+ QCOMPARE(signalResult(), QList<int>({0, 0}));
const QStringList words = { "foo", "bar" };
for (const QString &subString : words) {
QCOMPARE(findTextSync(m_page, subString), true);
- QCOMPARE(signalResult(), QVector<int>({1, 1}));
+ QCOMPARE(signalResult(), QList<int>({1, 1}));
QCOMPARE(findTextSync(m_page, ""), false);
- QCOMPARE(signalResult(), QVector<int>({0, 0}));
+ QCOMPARE(signalResult(), QList<int>({0, 0}));
}
QCOMPARE(findTextSync(m_page, "blahhh"), false);
- QCOMPARE(signalResult(), QVector<int>({0, 0}));
+ QCOMPARE(signalResult(), QList<int>({0, 0}));
QCOMPARE(findTextSync(m_page, ""), false);
- QCOMPARE(signalResult(), QVector<int>({0, 0}));
+ QCOMPARE(signalResult(), QList<int>({0, 0}));
}
void tst_QWebEnginePage::findTextSuccessiveShouldCallAllCallbacks()
{
- CallbackSpy<bool> spy1;
- CallbackSpy<bool> spy2;
- CallbackSpy<bool> spy3;
- CallbackSpy<bool> spy4;
- CallbackSpy<bool> spy5;
+ CallbackSpy<QWebEngineFindTextResult> spy1;
+ CallbackSpy<QWebEngineFindTextResult> spy2;
+ CallbackSpy<QWebEngineFindTextResult> spy3;
+ CallbackSpy<QWebEngineFindTextResult> spy4;
+ 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());
@@ -1103,15 +1304,15 @@ 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;
- m_view->page()->findText("foo", {}, [this, &callbackCalled](bool found) {
- QVERIFY(found);
+ m_view->page()->findText("foo", {}, [this, &callbackCalled](QWebEngineFindTextResult result) {
+ QVERIFY(result.numberOfMatches());
- m_view->page()->findText("bar", {}, [&callbackCalled](bool found) {
- QVERIFY(found);
+ m_view->page()->findText("bar", {}, [&callbackCalled](QWebEngineFindTextResult result) {
+ QVERIFY(result.numberOfMatches());
callbackCalled = true;
});
});
@@ -1140,12 +1341,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);
@@ -1153,28 +1354,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);
@@ -1184,45 +1385,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();
}
@@ -1234,18 +1450,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);
@@ -1256,29 +1482,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();
@@ -1288,19 +1518,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("αβγδεζηθικλμπ");
@@ -1328,6 +1564,8 @@ void tst_QWebEnginePage::deleteQWebEngineViewTwice()
}
}
+// TODO: Reimplement test without QStateMachine or add qtscxml module dependency
+#if defined(QT_STATEMACHINE_LIB)
class SpyForLoadSignalsOrder : public QStateMachine {
Q_OBJECT
public:
@@ -1385,6 +1623,7 @@ void tst_QWebEnginePage::loadSignalsOrder()
page.load(url);
QTRY_VERIFY_WITH_TIMEOUT(loadSpy.isFinished(), 20000);
}
+#endif // defined(QT_STATEMACHINE_LIB)
void tst_QWebEnginePage::renderWidgetHostViewNotShowTopLevel()
{
@@ -1651,9 +1890,9 @@ void tst_QWebEnginePage::savePage()
QWebEnginePage *page = view.page();
connect(page->profile(), &QWebEngineProfile::downloadRequested,
- [] (QWebEngineDownloadItem *item)
+ [] (QWebEngineDownloadRequest *item)
{
- connect(item, &QWebEngineDownloadItem::finished,
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged,
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop, Qt::QueuedConnection);
});
@@ -1667,7 +1906,7 @@ void tst_QWebEnginePage::savePage()
// Save the loaded page as HTML.
QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX");
const QString filePath = tempDir.path() + "/thingumbob.html";
- page->save(filePath, QWebEngineDownloadItem::CompleteHtmlSaveFormat);
+ page->save(filePath, QWebEngineDownloadRequest::CompleteHtmlSaveFormat);
QTestEventLoop::instance().enterLoop(10);
// Load something else.
@@ -1684,18 +1923,21 @@ void tst_QWebEnginePage::savePage()
void tst_QWebEnginePage::openWindowDefaultSize()
{
TestPage page;
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
QSignalSpy windowCreatedSpy(&page, SIGNAL(windowCreated()));
QWebEngineView view;
- page.setView(&view);
+ view.setPage(&page);
+ page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
+ view.setUrl(QUrl("about:blank"));
view.show();
+ QTRY_COMPARE(spyFinished.size(), 1);
- page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
// 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);
@@ -1766,7 +2008,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),
@@ -1783,7 +2025,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, [&]() {
@@ -1800,13 +2042,14 @@ void tst_QWebEnginePage::fullScreenRequested()
{
QWebEngineView view;
QWebEnginePage* page = view.page();
+ view.resize(640, 480);
view.show();
page->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
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"));
@@ -1820,6 +2063,13 @@ void tst_QWebEnginePage::fullScreenRequested()
QTest::keyPress(view.focusProxy(), Qt::Key_Space);
QTRY_VERIFY(isTrueJavaScriptResult(page, "document.webkitIsFullScreen"));
+
+ QTest::mouseMove(view.windowHandle(), QPoint(10,10));
+ QTest::mouseClick(view.windowHandle(), Qt::RightButton);
+ QTRY_COMPARE(view.findChildren<QMenu *>().size(), 1);
+ auto menu = view.findChildren<QMenu *>().first();
+ QVERIFY(menu->actions().contains(page->action(QWebEnginePage::ExitFullScreen)));
+
page->runJavaScript("document.webkitExitFullscreen()");
QTRY_VERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen"));
@@ -1830,8 +2080,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);
@@ -1839,35 +2099,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()
@@ -1882,13 +2130,14 @@ void tst_QWebEnginePage::symmetricUrl()
QUrl dataUrl("data:text/html,<h1>Test");
view.setUrl(dataUrl);
+ view.show();
QCOMPARE(view.url(), dataUrl);
QCOMPARE(view.history()->count(), 0);
// 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"));
@@ -1902,8 +2151,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.
@@ -1981,7 +2230,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()));
@@ -2002,11 +2251,11 @@ public:
{
close();
}
- virtual void abort() {}
- virtual void close() {}
+ void abort() override {}
+ void close() override {}
protected:
- qint64 readData(char*, qint64)
+ qint64 readData(char*, qint64) override
{
return 0;
}
@@ -2020,7 +2269,7 @@ private Q_SLOTS:
void continueError()
{
- emit error(this->error());
+ emit errorOccurred(this->error());
emit finished();
}
};
@@ -2034,11 +2283,11 @@ public:
FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { }
protected:
- virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
+ QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData) override
{
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;
@@ -2062,7 +2311,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());
@@ -2071,7 +2320,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());
@@ -2117,7 +2366,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);
@@ -2126,7 +2375,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);
@@ -2167,10 +2416,15 @@ void tst_QWebEnginePage::setHtmlWithBaseURL()
// This tests if baseUrl is indeed affecting the relative paths from resources.
// As we are using a local file as baseUrl, its security origin should be able to load local resources.
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
- QDir::setCurrent(TESTS_SOURCE_DIR);
+ QDir::setCurrent(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath());
+ qDebug()<<QDir::current();
QString html("<html><body><p>hello world</p><img src='resources/image2.png'/></body></html>");
@@ -2179,10 +2433,12 @@ void tst_QWebEnginePage::setHtmlWithBaseURL()
// in few seconds, the image should be completey loaded
QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
- page.setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
+ page.setHtml(html,
+ QUrl::fromLocalFile(
+ 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);
@@ -2199,7 +2455,7 @@ public:
int alerts;
protected:
- virtual void javaScriptAlert(const QUrl &securityOrigin, const QString &msg)
+ void javaScriptAlert(const QUrl &securityOrigin, const QString &msg) override
{
alerts++;
QCOMPARE(securityOrigin, QUrl(QStringLiteral("http://test.origin.com/")));
@@ -2228,9 +2484,6 @@ void tst_QWebEnginePage::setHtmlWithModuleImport()
"}\n");
rr->setResponseHeader("Content-Type", "text/javascript");
rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
}
});
QVERIFY(server.start());
@@ -2248,7 +2501,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));
}
@@ -2284,7 +2537,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);
@@ -2293,7 +2546,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);
@@ -2303,12 +2557,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();
@@ -2329,7 +2583,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());
}
@@ -2340,7 +2594,8 @@ signals:
void repaintRequested();
protected:
- bool event(QEvent *event) {
+ bool event(QEvent *event) override
+ {
if (event->type() == QEvent::UpdateRequest)
emit repaintRequested();
@@ -2363,7 +2618,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);
@@ -2379,9 +2634,13 @@ void tst_QWebEnginePage::setContent_data()
QString str = QString::fromUtf8("ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει");
QTest::newRow("UTF-8 plain text") << "text/plain; charset=utf-8" << str.toUtf8() << str;
- QTextCodec *utf16 = QTextCodec::codecForName("UTF-16");
- if (utf16)
- QTest::newRow("UTF-16 plain text") << "text/plain; charset=utf-16" << utf16->fromUnicode(str) << str;
+ QBuffer out16;
+ out16.open(QIODevice::WriteOnly);
+ QTextStream stream16(&out16);
+ stream16.setEncoding(QStringConverter::Utf16);
+ stream16 << str;
+ stream16.flush();
+ QTest::newRow("UTF-16 plain text") << "text/plain; charset=utf-16" << out16.buffer() << str;
str = QString::fromUtf8("Une chaîne de caractères à sa façon.");
QTest::newRow("latin-1 plain text") << "text/plain; charset=iso-8859-1" << str.toLatin1() << str;
@@ -2408,7 +2667,7 @@ public:
{
}
- virtual QNetworkReply* createRequest(Operation, const QNetworkRequest& request, QIODevice*)
+ QNetworkReply* createRequest(Operation, const QNetworkRequest& request, QIODevice*) override
{
QVariant cacheLoad = request.attribute(QNetworkRequest::CacheLoadControlAttribute);
if (cacheLoad.isValid())
@@ -2453,7 +2712,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);
@@ -2462,7 +2721,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);
@@ -2471,7 +2730,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);
@@ -2480,7 +2739,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);
@@ -2535,9 +2794,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());
@@ -2548,9 +2807,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());
@@ -2574,9 +2833,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());
@@ -2588,9 +2847,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());
@@ -2621,7 +2880,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.
@@ -2630,7 +2889,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);
@@ -2641,14 +2900,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.
@@ -2660,7 +2919,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.
@@ -2673,7 +2932,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()
@@ -2688,6 +2947,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);
@@ -2695,20 +2955,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(m_page->history()->count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(m_page->url(), url);
+ 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());
@@ -2716,7 +2978,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());
@@ -2745,9 +3007,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);
@@ -2761,11 +3023,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);
@@ -2775,31 +3037,17 @@ 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);
QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad2));
}
-void tst_QWebEnginePage::loadFinishedAfterNotFoundError()
-{
- QWebEnginePage page;
- QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
-
- page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
- page.setUrl(QUrl("http://non.existent/url"));
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000);
-
- page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
- page.setUrl(QUrl("http://another.non.existent/url"));
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000);
-}
-
class URLSetter : public QObject {
Q_OBJECT
@@ -2881,11 +3129,7 @@ void tst_QWebEnginePage::loadInSignalHandlers()
URLSetter setter(m_page, signal, type, urlForSetter);
QSignalSpy spy(&setter, &URLSetter::finished);
m_page->load(url);
- // every loadStarted() call should have also loadFinished()
- if (signal == URLSetter::LoadStarted)
- QTRY_COMPARE(spy.count(), 2);
- else
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_VERIFY_WITH_TIMEOUT(spy.size() >= 1, 20000);
QCOMPARE(m_page->url(), urlForSetter);
}
@@ -2896,31 +3140,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);
}
@@ -2937,7 +3181,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));
@@ -2947,7 +3191,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));
@@ -2970,42 +3214,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()
@@ -3025,17 +3286,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);
@@ -3064,34 +3328,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;
@@ -3100,12 +3347,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()));
@@ -3126,7 +3373,8 @@ void tst_QWebEnginePage::viewSourceURL_data()
QTest::newRow("view-source:") << QUrl("view-source:") << true << QUrl("view-source:") << QUrl("about:blank") << QString("view-source:");
QTest::newRow("view-source:about:blank") << QUrl("view-source:about:blank") << true << QUrl("view-source:about:blank") << QUrl("about:blank") << QString("view-source:about:blank");
- QString localFilePath = QString("%1qwebenginepage/resources/test1.html").arg(TESTS_SOURCE_DIR);
+ QString localFilePath =
+ QString("%1/resources/test1.html").arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath());
QUrl testLocalUrl = QUrl(QString("view-source:%1").arg(QUrl::fromLocalFile(localFilePath).toString()));
QUrl testLocalUrlWithoutScheme = QUrl(QString("view-source:%1").arg(localFilePath));
QTest::newRow(testLocalUrl.toString().toStdString().c_str()) << testLocalUrl << true << testLocalUrl << QUrl::fromLocalFile(localFilePath) << QString("test1.html");
@@ -3142,8 +3390,12 @@ void tst_QWebEnginePage::viewSourceURL_data()
void tst_QWebEnginePage::viewSourceURL()
{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
QFETCH(QUrl, userInputUrl);
QFETCH(bool, loadSucceed);
@@ -3155,7 +3407,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);
@@ -3190,7 +3442,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)));
@@ -3212,7 +3464,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()
@@ -3235,19 +3487,17 @@ void tst_QWebEnginePage::registerProtocolHandler()
} else if (rr->requestMethod() == "GET" && rr->requestPath() == "/mail?uri=mailto%3Afoo%40bar.com") {
mailRequestCount++;
rr->sendResponse();
- } else {
- rr->setResponseStatus(404);
- rr->sendResponse();
}
});
QVERIFY(server.start());
- QWebEnginePage page;
+ QWebEngineProfile profile(QStringLiteral("registerProtocolHandler%1").arg(QTest::currentDataTag()));
+ QWebEnginePage page(&profile, nullptr);
QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
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\")");
@@ -3257,7 +3507,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);
@@ -3268,7 +3518,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());
@@ -3279,22 +3529,12 @@ void tst_QWebEnginePage::dataURLFragment()
m_view->resize(800, 600);
m_view->show();
QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
-
- m_page->setHtml("<html><body>"
- "<a id='link' href='#anchor'>anchor</a>"
- "</body></html>");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
-
QSignalSpy urlChangedSpy(m_page, SIGNAL(urlChanged(QUrl)));
- QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link"));
- QVERIFY(urlChangedSpy.wait());
- QCOMPARE(m_page->url().fragment(), QStringLiteral("anchor"));
-
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(), 2);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link"));
QVERIFY(urlChangedSpy.wait());
@@ -3318,7 +3558,7 @@ void tst_QWebEnginePage::devTools()
QCOMPARE(devToolsPage.devToolsPage(), nullptr);
QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage1);
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000);
+ QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 90000);
QVERIFY(spy.takeFirst().value(0).toBool());
devToolsPage.setInspectedPage(&inspectedPage2);
@@ -3330,7 +3570,7 @@ void tst_QWebEnginePage::devTools()
QCOMPARE(devToolsPage.devToolsPage(), nullptr);
QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage2);
- QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000);
+ QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 90000);
QVERIFY(spy.takeFirst().value(0).toBool());
devToolsPage.setInspectedPage(nullptr);
@@ -3341,19 +3581,20 @@ void tst_QWebEnginePage::devTools()
QCOMPARE(inspectedPage2.inspectedPage(), nullptr);
QCOMPARE(devToolsPage.devToolsPage(), nullptr);
QCOMPARE(devToolsPage.inspectedPage(), nullptr);
+
+ QVERIFY(!inspectedPage1.devToolsId().isEmpty());
}
void tst_QWebEnginePage::openLinkInDifferentProfile()
{
- class Page : public QWebEnginePage {
- public:
- QWebEnginePage *targetPage = nullptr;
- Page(QWebEngineProfile *profile) : QWebEnginePage(profile) {}
- private:
- QWebEnginePage *createWindow(WebWindowType) override { return targetPage; }
- };
+ QWebEnginePage *targetPage = nullptr;
QWebEngineProfile profile1, profile2;
- Page page1(&profile1), page2(&profile2);
+ profile1.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile1));
+ profile2.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile2));
+ QWebEnginePage page1(&profile1), page2(&profile2);
+ connect(&page1, &QWebEnginePage::newWindowRequested, [&](QWebEngineNewWindowRequest &request) {
+ request.openIn(targetPage);
+ });
QWebEngineView view;
view.resize(500, 500);
view.setPage(&page1);
@@ -3361,13 +3602,13 @@ void tst_QWebEnginePage::openLinkInDifferentProfile()
QVERIFY(QTest::qWaitForWindowExposed(&view));
QSignalSpy spy1(&page1, &QWebEnginePage::loadFinished), spy2(&page2, &QWebEnginePage::loadFinished);
page1.setHtml("<html><body>"
- "<a id='link' href='data:,hello'>link</a>"
- "</body></html>");
- QTRY_COMPARE(spy1.count(), 1);
+ "<a id='link' href='hello'>link</a>"
+ "</body></html>", QUrl("echo:/"));
+ QTRY_COMPARE(spy1.size(), 1);
QVERIFY(spy1.takeFirst().value(0).toBool());
- page1.targetPage = &page2;
+ 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());
}
@@ -3427,7 +3668,7 @@ void tst_QWebEnginePage::openLinkInNewPage_data()
// the disposition and performing the navigation request normally.
QTest::newRow("BlockPopup") << Decision::ReturnNull << Cause::TargetBlank << Effect::Blocked;
- QTest::newRow("IgnoreIntent") << Decision::ReturnNull << Cause::MiddleClick << Effect::LoadInSelf;
+ QTest::newRow("IgnoreIntent") << Decision::ReturnNull << Cause::MiddleClick << Effect::Blocked;
QTest::newRow("OverridePopup") << Decision::ReturnSelf << Cause::TargetBlank << Effect::LoadInSelf;
QTest::newRow("OverrideIntent") << Decision::ReturnSelf << Cause::MiddleClick << Effect::LoadInSelf;
QTest::newRow("AcceptPopup") << Decision::ReturnOther << Cause::TargetBlank << Effect::LoadInOther;
@@ -3465,6 +3706,7 @@ void tst_QWebEnginePage::openLinkInNewPage()
QFETCH(Effect, effect);
QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile));
Page page1(&profile);
Page page2(&profile);
View view1(&page1);
@@ -3474,9 +3716,9 @@ void tst_QWebEnginePage::openLinkInNewPage()
QVERIFY(QTest::qWaitForWindowExposed(&view1));
page1.setHtml("<html><body>"
- "<a id='link' href='data:,hello' target='_blank'>link</a>"
- "</body></html>");
- QTRY_COMPARE(page1.spy.count(), 1);
+ "<a id='link' href='hello' target='_blank'>link</a>"
+ "</body></html>", QUrl("echo:/"));
+ QTRY_COMPARE(page1.spy.size(), 1);
QVERIFY(page1.spy.takeFirst().value(0).toBool());
switch (decision) {
@@ -3491,7 +3733,7 @@ void tst_QWebEnginePage::openLinkInNewPage()
break;
}
- Qt::MouseButton button;
+ Qt::MouseButton button = Qt::NoButton;
switch (cause) {
case Cause::TargetBlank:
button = Qt::LeftButton;
@@ -3504,12 +3746,15 @@ void tst_QWebEnginePage::openLinkInNewPage()
switch (effect) {
case Effect::Blocked:
- // Nothing to test
+ // Test nothing new loaded
+ QTest::qWait(500);
+ 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);
@@ -3518,9 +3763,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;
@@ -3542,7 +3787,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"));
}
@@ -3618,7 +3863,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"));
@@ -3676,6 +3921,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);
@@ -3686,8 +4074,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);
@@ -3704,6 +4092,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");
@@ -3715,64 +4157,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));
@@ -3781,21 +4223,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));
}
@@ -3811,18 +4253,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);
@@ -3831,28 +4273,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);
@@ -3861,31 +4303,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));
}
@@ -3896,7 +4338,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
@@ -3933,7 +4375,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
@@ -3972,7 +4414,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
@@ -3997,16 +4439,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, 30000);
+ QTRY_COMPARE_WITH_TIMEOUT(inspectedSpy.size(), 1, 90000);
QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true));
- QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 30000);
+ 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(devToolsSpy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000);
QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
inspectedPage.setDevToolsPage(nullptr);
@@ -4014,9 +4456,9 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools()
inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
inspectedPage.setDevToolsPage(&devToolsPage);
QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
- QTRY_COMPARE(devToolsSpy.count(), 1);
+ 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);
@@ -4024,7 +4466,7 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools()
devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
devToolsPage.setInspectedPage(&inspectedPage);
QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
- QTRY_COMPARE(devToolsSpy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000);
QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
devToolsPage.setInspectedPage(nullptr);
@@ -4032,8 +4474,7 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools()
devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
devToolsPage.setInspectedPage(&inspectedPage);
QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
- QTRY_COMPARE(devToolsSpy.count(), 2);
- QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(false));
+ QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000);
QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
// keep DevTools open
@@ -4071,35 +4512,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);
}
@@ -4116,21 +4557,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());
}
@@ -4146,14 +4587,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));
@@ -4163,21 +4604,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);
}
@@ -4273,32 +4714,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));
}
@@ -4313,33 +4754,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));
}
@@ -4358,20 +4799,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"));
}
@@ -4391,13 +4832,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"));
}
@@ -4417,15 +4858,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"));
}
@@ -4441,8 +4882,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());
@@ -4454,7 +4895,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"));
@@ -4468,6 +4909,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;
@@ -4480,55 +4943,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()
@@ -4569,6 +5061,141 @@ void tst_QWebEnginePage::renderProcessPid()
QCOMPARE(m_page->renderProcessPid(), 0);
}
+class FileSelectionTestPage : public QWebEnginePage {
+public:
+ 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() << (m_tempDir.path() + "/file.txt");
+ }
+
+ QTemporaryDir m_tempDir;
+ int chosenFileSelectionMode = -1;
+ QStringList chosenAcceptedMimeTypes;
+};
+
+void tst_QWebEnginePage::testChooseFilesParameters_data()
+{
+ QTest::addColumn<QString>("uploadAttribute");
+ QTest::addColumn<QString>("mimeTypeAttribute");
+ QTest::addColumn<QWebEnginePage::FileSelectionMode>("expectedFileSelectionMode");
+ QTest::addColumn<QStringList>("expectedMimeType");
+ QStringList mimeTypes;
+
+ QTest::addRow("Single file upload") << QString() << QString()
+ << QWebEnginePage::FileSelectOpen << QStringList();
+ QTest::addRow("Multiple file upload") << QString("multiple") << QString()
+ << 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;
+ mimeTypes = QStringList() << "video/*";
+ QTest::addRow("MIME type: video") << QString() << QString("accept='%1'").arg(mimeTypes.join(','))
+ << QWebEnginePage::FileSelectOpen << mimeTypes;
+ mimeTypes = QStringList() << "image/*";
+ QTest::addRow("MIME type: image") << QString() << QString("accept='%1'").arg(mimeTypes.join(','))
+ << QWebEnginePage::FileSelectOpen << mimeTypes;
+ mimeTypes = QStringList() << ".txt" << ".html";
+ QTest::addRow("MIME type: custom") << QString() << QString("accept='%1'").arg(mimeTypes.join(','))
+ << QWebEnginePage::FileSelectOpen << mimeTypes;
+ mimeTypes = QStringList() << "audio/*" << "video/*" << "image/*" << ".txt" << ".html";
+ QTest::addRow("Multiple MIME types") << QString() << QString("accept='%1'").arg(mimeTypes.join(','))
+ << QWebEnginePage::FileSelectOpen << mimeTypes;
+}
+
+void tst_QWebEnginePage::testChooseFilesParameters()
+{
+ QFETCH(QString, uploadAttribute);
+ QFETCH(QString, mimeTypeAttribute);
+ QFETCH(QWebEnginePage::FileSelectionMode, expectedFileSelectionMode);
+ QFETCH(QStringList, expectedMimeType);
+
+ FileSelectionTestPage page;
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+
+ QWebEngineView view;
+ view.resize(500, 500);
+ view.setPage(&page);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ 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.size(), 1);
+
+ evaluateJavaScriptSync(view.page(), "document.getElementById('filePicker').focus()");
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("filePicker"));
+ QTest::keyClick(view.focusProxy(), Qt::Key_Enter);
+
+ QTRY_COMPARE(page.chosenFileSelectionMode, expectedFileSelectionMode);
+ QTRY_COMPARE(page.chosenAcceptedMimeTypes, expectedMimeType);
+}
+
+void tst_QWebEnginePage::fileSystemAccessDialog()
+{
+ FileSelectionTestPage page;
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+
+ QWebEngineView view;
+ view.resize(500, 500);
+ view.setPage(&page);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ 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='getTemporaryDir()'"
+ "</body></html>"),
+ QString("qrc:/"));
+ QVERIFY(spyFinished.wait());
+ 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.title(), "New value");
+
+ QTRY_COMPARE(page.chosenFileSelectionMode, QWebEnginePage::FileSelectSave);
+ QTRY_COMPARE(page.chosenAcceptedMimeTypes, QStringList());
+}
+
void tst_QWebEnginePage::backgroundColor()
{
QWebEngineProfile profile;
@@ -4622,24 +5249,27 @@ 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));
}
void tst_QWebEnginePage::closeContents()
{
TestPage page;
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
QSignalSpy windowCreatedSpy(&page, &TestPage::windowCreated);
+ page.setUrl(QUrl("about:blank"));
+ 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];
- dialogPage->setView(dialogView);
+ dialogView->setPage(dialogPage);
QCOMPARE(dialogPage->lifecycleState(), QWebEnginePage::LifecycleState::Active);
// This should not crash.
@@ -4662,8 +5292,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/");
}
@@ -4676,11 +5306,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)
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
deleted file mode 100644
index 013a307de..000000000
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/content.html</file>
- <file>resources/dynamicFrame.html</file>
- <file>resources/index.html</file>
- <file>resources/frame_a.html</file>
- <file>resources/frame_c.html</file>
- <file>resources/iframe.html</file>
- <file>resources/iframe2.html</file>
- <file>resources/iframe3.html</file>
- <file>resources/framedindex.html</file>
- <file>resources/fullscreen.html</file>
- <file>resources/script.html</file>
- <file>resources/user.css</file>
- <file>resources/image.png</file>
- <file>resources/pasteimage.html</file>
- <file>resources/reload.html</file>
- <file>resources/style.css</file>
- <file>resources/test1.html</file>
- <file>resources/test2.html</file>
- <file>resources/testiframe.html</file>
- <file>resources/testiframe2.html</file>
- <file>resources/foo.txt</file>
- <file>resources/bar.txt</file>
- <file>resources/path with spaces.txt</file>
- <file>resources/lifecycle.html</file>
-</qresource>
-<qresource prefix='/shared'>
- <file alias='notification.html'>../../shared/data/notification.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/qwebengineprofile/CMakeLists.txt b/tests/auto/widgets/qwebengineprofile/CMakeLists.txt
new file mode 100644
index 000000000..d7393eaef
--- /dev/null
+++ b/tests/auto/widgets/qwebengineprofile/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../httpserver/httpserver.cmake)
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebengineprofile
+ SOURCES
+ tst_qwebengineprofile.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::HttpServer
+ Test::Util
+)
diff --git a/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro b/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro
deleted file mode 100644
index ca16cee39..000000000
--- a/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-include(../tests.pri)
-include(../../shared/http.pri)
-exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
-QT *= core-private gui-private
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 00d4bae5a..cebdaaa47 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "../util.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <util.h>
#include <QtCore/qbuffer.h>
#include <QtCore/qmimedatabase.h>
#include <QtTest/QtTest>
@@ -35,11 +10,11 @@
#include <QtWebEngineCore/qwebenginecookiestore.h>
#include <QtWebEngineCore/qwebengineurlscheme.h>
#include <QtWebEngineCore/qwebengineurlschemehandler.h>
-#include <QtWebEngineWidgets/qwebengineprofile.h>
-#include <QtWebEngineWidgets/qwebenginepage.h>
-#include <QtWebEngineWidgets/qwebenginesettings.h>
+#include <QtWebEngineCore/qwebenginesettings.h>
+#include <QtWebEngineCore/qwebengineprofile.h>
+#include <QtWebEngineCore/qwebenginepage.h>
+#include <QtWebEngineCore/qwebenginedownloadrequest.h>
#include <QtWebEngineWidgets/qwebengineview.h>
-#include <QtWebEngineWidgets/qwebenginedownloaditem.h>
#if QT_CONFIG(webengine_webchannel)
#include <QWebChannel>
@@ -57,16 +32,16 @@ class tst_QWebEngineProfile : public QObject
private Q_SLOTS:
void initTestCase();
- void init();
- void cleanup();
- void privateProfile();
- void testProfile();
+ void defaultProfile_data();
+ void defaultProfile();
+ void userDefinedProfile();
void clearDataFromCache();
void disableCache();
void urlSchemeHandlers();
void urlSchemeHandlerFailRequest();
void urlSchemeHandlerFailOnRead();
void urlSchemeHandlerStreaming();
+ void urlSchemeHandlerStreaming2();
void urlSchemeHandlerRequestHeaders();
void urlSchemeHandlerInstallation();
void urlSchemeHandlerXhrStatus();
@@ -78,7 +53,6 @@ private Q_SLOTS:
void changePersistentPath();
void changeHttpUserAgent();
void changeHttpAcceptLanguage();
- void changeUseForGlobalCertificateVerification();
void changePersistentCookiesPolicy();
void initiator();
void badDeleteOrder();
@@ -105,61 +79,48 @@ void tst_QWebEngineProfile::initTestCase()
QWebEngineUrlScheme::registerScheme(myscheme);
}
-void tst_QWebEngineProfile::init()
-{
- //make sure defualt global profile is 'default' across all the tests
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- QVERIFY(!profile->isOffTheRecord());
- QCOMPARE(profile->storageName(), QStringLiteral("Default"));
- QCOMPARE(profile->httpCacheType(), QWebEngineProfile::DiskHttpCache);
- QCOMPARE(profile->persistentCookiesPolicy(), QWebEngineProfile::AllowPersistentCookies);
- QCOMPARE(profile->cachePath(), QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- + QStringLiteral("/QtWebEngine/Default"));
- QCOMPARE(profile->persistentStoragePath(), QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + QStringLiteral("/QtWebEngine/Default"));
-}
+static QString StandardCacheLocation() { static auto p = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); return p; }
+static QString StandardAppDataLocation() { static auto p = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); return p; }
-void tst_QWebEngineProfile::cleanup()
+void tst_QWebEngineProfile::defaultProfile_data()
{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- profile->setCachePath(QString());
- profile->setPersistentStoragePath(QString());
- profile->setHttpCacheType(QWebEngineProfile::DiskHttpCache);
- profile->removeAllUrlSchemeHandlers();
+ QTest::addColumn<bool>("userCreated");
+ QTest::addRow("global") << false;
+ QTest::addRow("user") << true;
}
-void tst_QWebEngineProfile::privateProfile()
+void tst_QWebEngineProfile::defaultProfile()
{
- QWebEngineProfile otrProfile;
- QVERIFY(otrProfile.isOffTheRecord());
- QCOMPARE(otrProfile.httpCacheType(), QWebEngineProfile::MemoryHttpCache);
- QCOMPARE(otrProfile.persistentCookiesPolicy(), QWebEngineProfile::NoPersistentCookies);
- QCOMPARE(otrProfile.cachePath(), QString());
- QCOMPARE(otrProfile.persistentStoragePath(), QString());
+ QFETCH(bool, userCreated);
+ QScopedPointer<QWebEngineProfile> p(userCreated ? new QWebEngineProfile : nullptr);
+ QWebEngineProfile *profile = userCreated ? p.get() : QWebEngineProfile::defaultProfile();
+ QVERIFY(profile);
+ QVERIFY(profile->isOffTheRecord());
+ QCOMPARE(profile->storageName(), QString());
+ QCOMPARE(profile->httpCacheType(), QWebEngineProfile::MemoryHttpCache);
+ QCOMPARE(profile->persistentCookiesPolicy(), QWebEngineProfile::NoPersistentCookies);
+ QCOMPARE(profile->cachePath(), QString());
+ QCOMPARE(profile->persistentStoragePath(), StandardAppDataLocation() + QStringLiteral("/QtWebEngine/OffTheRecord"));
// TBD: setters do not really work
- otrProfile.setCachePath(QStringLiteral("/home/foo/bar"));
- QCOMPARE(otrProfile.cachePath(), QString());
- otrProfile.setPersistentStoragePath(QStringLiteral("/home/foo/bar"));
- QCOMPARE(otrProfile.persistentStoragePath(), QString());
- otrProfile.setHttpCacheType(QWebEngineProfile::DiskHttpCache);
- QCOMPARE(otrProfile.httpCacheType(), QWebEngineProfile::MemoryHttpCache);
- otrProfile.setPersistentCookiesPolicy(QWebEngineProfile::ForcePersistentCookies);
- QCOMPARE(otrProfile.persistentCookiesPolicy(), QWebEngineProfile::NoPersistentCookies);
+ profile->setCachePath(QStringLiteral("/home/foo/bar"));
+ QCOMPARE(profile->cachePath(), QString());
+ profile->setPersistentStoragePath(QStringLiteral("/home/foo/bar"));
+ QCOMPARE(profile->persistentStoragePath(), QStringLiteral("/home/foo/bar"));
+ profile->setHttpCacheType(QWebEngineProfile::DiskHttpCache);
+ QCOMPARE(profile->httpCacheType(), QWebEngineProfile::MemoryHttpCache);
+ profile->setPersistentCookiesPolicy(QWebEngineProfile::ForcePersistentCookies);
+ QCOMPARE(profile->persistentCookiesPolicy(), QWebEngineProfile::NoPersistentCookies);
}
-
-void tst_QWebEngineProfile::testProfile()
+void tst_QWebEngineProfile::userDefinedProfile()
{
QWebEngineProfile profile(QStringLiteral("Test"));
QVERIFY(!profile.isOffTheRecord());
QCOMPARE(profile.storageName(), QStringLiteral("Test"));
QCOMPARE(profile.httpCacheType(), QWebEngineProfile::DiskHttpCache);
QCOMPARE(profile.persistentCookiesPolicy(), QWebEngineProfile::AllowPersistentCookies);
- QCOMPARE(profile.cachePath(), QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- + QStringLiteral("/QtWebEngine/Test"));
- QCOMPARE(profile.persistentStoragePath(), QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + QStringLiteral("/QtWebEngine/Test"));
+ QCOMPARE(profile.cachePath(), StandardCacheLocation() + QStringLiteral("/QtWebEngine/Test"));
+ QCOMPARE(profile.persistentStoragePath(), StandardAppDataLocation() + QStringLiteral("/QtWebEngine/Test"));
}
class AutoDir : public QDir
@@ -197,14 +158,12 @@ public:
private:
void onNewRequest(HttpReqRep *rr)
{
- const QDir resourceDir(TESTS_SOURCE_DIR "qwebengineprofile/resources");
+ const QDir resourceDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + "/resources");
QString path = rr->requestPath();
path.remove(0, 1);
- if (rr->requestMethod() != "GET" || !resourceDir.exists(path))
- {
- rr->setResponseStatus(404);
- rr->sendResponse();
+ if (rr->requestMethod() != "GET" || !resourceDir.exists(path)) {
+ rr->sendResponse(404);
return;
}
@@ -229,8 +188,10 @@ void tst_QWebEngineProfile::clearDataFromCache()
QVERIFY(server.start());
AutoDir cacheDir("./tst_QWebEngineProfile_clearDataFromCache");
+ QVERIFY(!cacheDir.exists("Cache"));
- QWebEngineProfile profile(QStringLiteral("Test"));
+ QWebEngineProfile profile(QStringLiteral("clearDataFromCache"));
+ QSignalSpy cacheSpy(&profile, &QWebEngineProfile::clearHttpCacheCompleted);
profile.setCachePath(cacheDir.path());
profile.setHttpCacheType(QWebEngineProfile::DiskHttpCache);
@@ -241,10 +202,14 @@ void tst_QWebEngineProfile::clearDataFromCache()
QVERIFY(cacheDir.exists("Cache"));
qint64 sizeBeforeClear = totalSize(cacheDir);
+ QCOMPARE_GT(sizeBeforeClear, 0);
profile.clearHttpCache();
- // Wait for cache to be cleared.
- QTest::qWait(1000);
- QVERIFY(sizeBeforeClear > totalSize(cacheDir));
+ QTRY_COMPARE(cacheSpy.size(), 1);
+#if defined(Q_OS_WIN)
+ QTRY_COMPARE_GT(sizeBeforeClear, totalSize(cacheDir));
+#else
+ QCOMPARE_GT(sizeBeforeClear, totalSize(cacheDir));
+#endif
(void)server.stop();
}
@@ -256,18 +221,18 @@ void tst_QWebEngineProfile::disableCache()
AutoDir cacheDir("./tst_QWebEngineProfile_disableCache");
- QWebEnginePage page;
- QWebEngineProfile *profile = page.profile();
- profile->setCachePath(cacheDir.path());
+ QWebEngineProfile profile("disableCache");
+ QWebEnginePage page(&profile);
+ profile.setCachePath(cacheDir.path());
QVERIFY(!cacheDir.exists("Cache"));
- profile->setHttpCacheType(QWebEngineProfile::NoCache);
+ profile.setHttpCacheType(QWebEngineProfile::NoCache);
// Wait for cache to be cleared.
QTest::qWait(1000);
QVERIFY(loadSync(&page, server.url("/hedgehog.html")));
QVERIFY(!cacheDir.exists("Cache"));
- profile->setHttpCacheType(QWebEngineProfile::DiskHttpCache);
+ profile.setHttpCacheType(QWebEngineProfile::DiskHttpCache);
QVERIFY(loadSync(&page, server.url("/hedgehog.html")));
QVERIFY(cacheDir.exists("Cache"));
@@ -277,7 +242,7 @@ void tst_QWebEngineProfile::disableCache()
class RedirectingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
{
public:
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
job->redirect(QUrl(QStringLiteral("data:text/plain;charset=utf-8,")
+ job->requestUrl().fileName()));
@@ -295,7 +260,7 @@ public:
{
}
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
QBuffer *buffer = new QBuffer(job);
buffer->setData(job->requestUrl().toString().toUtf8());
@@ -306,10 +271,12 @@ public:
QList<QPointer<QBuffer>> m_buffers;
};
-class StreamingIODevice : public QIODevice {
+// an evil version constantly claiming to be at end, similar to QNetworkReply
+class StreamingIODeviceBasic : public QIODevice
+{
Q_OBJECT
public:
- StreamingIODevice(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0)
+ StreamingIODeviceBasic(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0)
{
setOpenMode(QIODevice::ReadOnly);
m_timer.start(100, this);
@@ -320,12 +287,11 @@ public:
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
return m_bytesAvailable;
}
- bool atEnd() const override
+protected:
+ bool internalAtEnd() const
{
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
return (m_data.size() >= 1000 && m_bytesRead >= 1000);
}
-protected:
void timerEvent(QTimerEvent *) override
{
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
@@ -346,7 +312,7 @@ protected:
memcpy(data, m_data.constData() + m_bytesRead, len);
m_bytesAvailable -= len;
m_bytesRead += len;
- } else if (atEnd())
+ } else if (internalAtEnd())
return -1;
return len;
@@ -356,19 +322,26 @@ protected:
return 0;
}
-private:
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- mutable QMutex m_mutex{QMutex::Recursive};
- using QRecursiveMutex = QMutex;
-#else
mutable QRecursiveMutex m_mutex;
-#endif
+private:
QByteArray m_data;
QBasicTimer m_timer;
int m_bytesRead;
int m_bytesAvailable;
};
+// A nicer version implementing atEnd
+class StreamingIODevice : public StreamingIODeviceBasic
+{
+public:
+ StreamingIODevice(QObject *parent) : StreamingIODeviceBasic(parent) {}
+ bool atEnd() const override
+ {
+ const std::lock_guard<QRecursiveMutex> lock(m_mutex);
+ return internalAtEnd();
+ }
+};
+
class StreamingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
{
public:
@@ -377,12 +350,26 @@ public:
{
}
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
job->reply("text/plain;charset=utf-8", new StreamingIODevice(job));
}
};
+class StreamingUrlSchemeHandler2 : public QWebEngineUrlSchemeHandler
+{
+public:
+ StreamingUrlSchemeHandler2(QObject *parent = nullptr)
+ : QWebEngineUrlSchemeHandler(parent)
+ {
+ }
+
+ void requestStarted(QWebEngineUrlRequestJob *job) override
+ {
+ job->reply("text/plain;charset=utf-8", new StreamingIODeviceBasic(job));
+ }
+};
+
void tst_QWebEngineProfile::urlSchemeHandlers()
{
RedirectingUrlSchemeHandler lettertoHandler;
@@ -392,42 +379,42 @@ void tst_QWebEngineProfile::urlSchemeHandlers()
view.setPage(new QWebEnginePage(&profile, &view));
view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
QString emailAddress = QStringLiteral("egon@olsen-banden.dk");
- QVERIFY(loadSync(&view, QUrl(QStringLiteral("letterto:") + emailAddress)));
+ QVERIFY(loadSync(view.page(), QUrl(QStringLiteral("letterto:") + emailAddress)));
QCOMPARE(toPlainTextSync(view.page()), emailAddress);
// Install a gopher handler after the view has been fully initialized.
ReplyingUrlSchemeHandler gopherHandler;
profile.installUrlSchemeHandler("gopher", &gopherHandler);
QUrl url = QUrl(QStringLiteral("gopher://olsen-banden.dk/benny"));
- QVERIFY(loadSync(&view, url));
+ QVERIFY(loadSync(view.page(), url));
QCOMPARE(toPlainTextSync(view.page()), url.toString());
// Remove the letterto scheme, and check whether it is not handled anymore.
profile.removeUrlScheme("letterto");
emailAddress = QStringLiteral("kjeld@olsen-banden.dk");
- QVERIFY(loadSync(&view, QUrl(QStringLiteral("letterto:") + emailAddress), false));
+ QVERIFY(loadSync(view.page(), QUrl(QStringLiteral("letterto:") + emailAddress), false));
QVERIFY(toPlainTextSync(view.page()) != emailAddress);
// Check if gopher is still working after removing letterto.
url = QUrl(QStringLiteral("gopher://olsen-banden.dk/yvonne"));
- QVERIFY(loadSync(&view, url));
+ QVERIFY(loadSync(view.page(), url));
QCOMPARE(toPlainTextSync(view.page()), url.toString());
// Does removeAll work?
profile.removeAllUrlSchemeHandlers();
url = QUrl(QStringLiteral("gopher://olsen-banden.dk/harry"));
- QVERIFY(loadSync(&view, url, false));
+ QVERIFY(loadSync(view.page(), url, false));
QVERIFY(toPlainTextSync(view.page()) != url.toString());
// Install a handler that is owned by the view. Make sure this doesn't crash on shutdown.
profile.installUrlSchemeHandler("aviancarrier", new ReplyingUrlSchemeHandler(&view));
url = QUrl(QStringLiteral("aviancarrier:inspector.mortensen@politistyrke.dk"));
- QVERIFY(loadSync(&view, url));
+ QVERIFY(loadSync(view.page(), url));
QCOMPARE(toPlainTextSync(view.page()), url.toString());
// Check that all buffers got deleted
- QCOMPARE(gopherHandler.m_buffers.count(), 2);
- for (int i = 0; i < gopherHandler.m_buffers.count(); ++i)
+ QCOMPARE(gopherHandler.m_buffers.size(), 2);
+ for (int i = 0; i < gopherHandler.m_buffers.size(); ++i)
QVERIFY(gopherHandler.m_buffers.at(i).isNull());
}
@@ -487,7 +474,8 @@ void tst_QWebEngineProfile::urlSchemeHandlerFailRequest()
view.setPage(new QWebEnginePage(&profile, &view));
view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
view.load(QUrl(QStringLiteral("foo://bar")));
- QVERIFY(loadFinishedSpy.wait());
+ view.show();
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
QCOMPARE(toPlainTextSync(view.page()), QString());
}
@@ -501,7 +489,8 @@ void tst_QWebEngineProfile::urlSchemeHandlerFailOnRead()
view.setPage(new QWebEnginePage(&profile, &view));
view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
view.load(QUrl(QStringLiteral("foo://bar")));
- QVERIFY(loadFinishedSpy.wait());
+ view.show();
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
QCOMPARE(toPlainTextSync(view.page()), QString());
}
@@ -515,7 +504,25 @@ void tst_QWebEngineProfile::urlSchemeHandlerStreaming()
view.setPage(new QWebEnginePage(&profile, &view));
view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
view.load(QUrl(QStringLiteral("stream://whatever")));
- QVERIFY(loadFinishedSpy.wait());
+ view.show();
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
+ QByteArray result;
+ result.append(1000, 'c');
+ QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result));
+}
+
+void tst_QWebEngineProfile::urlSchemeHandlerStreaming2()
+{
+ StreamingUrlSchemeHandler2 handler;
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("stream", &handler);
+ QWebEngineView view;
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.setPage(new QWebEnginePage(&profile, &view));
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ view.load(QUrl(QStringLiteral("stream://whatever")));
+ view.show();
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
QByteArray result;
result.append(1000, 'c');
QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result));
@@ -576,7 +583,7 @@ void tst_QWebEngineProfile::urlSchemeHandlerRequestHeaders()
QWebEnginePage page(&profile);
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.load(QUrl(QStringLiteral("myscheme://whatever")));
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
}
void tst_QWebEngineProfile::urlSchemeHandlerInstallation()
@@ -648,7 +655,7 @@ private:
class XhrStatusUrlSchemeHandler : public QWebEngineUrlSchemeHandler
{
public:
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
QString path = job->requestUrl().path();
if (path == "/") {
@@ -708,7 +715,7 @@ void tst_QWebEngineProfile::urlSchemeHandlerXhrStatus()
profile.installUrlSchemeHandler("aviancarrier", &handler);
page.setWebChannel(&channel);
page.load(QUrl("aviancarrier:/"));
- QTRY_VERIFY(host.isReady());
+ QTRY_VERIFY_WITH_TIMEOUT(host.isReady(), 30000);
host.load(QUrl("aviancarrier:/ok"));
host.load(QUrl("aviancarrier:/redirect"));
host.load(QUrl("aviancarrier:/fail"));
@@ -726,7 +733,7 @@ void tst_QWebEngineProfile::urlSchemeHandlerXhrStatus()
class ScriptsUrlSchemeHandler : public QWebEngineUrlSchemeHandler
{
public:
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
auto *script = new QBuffer(job);
script->setData(QByteArrayLiteral("window.test = 'SUCCESS';"));
@@ -742,12 +749,12 @@ void tst_QWebEngineProfile::urlSchemeHandlerScriptModule()
QWebEnginePage page(&profile);
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.setHtml(QStringLiteral("<html><head><script src=\"aviancarrier:///\"></script></head><body>Test1</body></html>"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("test")).toString(), QStringLiteral("SUCCESS"));
loadFinishedSpy.clear();
page.setHtml(QStringLiteral("<html><head><script type=\"module\" src=\"aviancarrier:///\"></script></head><body>Test2</body></html>"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("test")).toString(), QStringLiteral("SUCCESS"));
}
@@ -757,7 +764,7 @@ public:
LongReplyUrlSchemeHandler(QObject *parent = nullptr) : QWebEngineUrlSchemeHandler(parent) {}
~LongReplyUrlSchemeHandler() {}
- void requestStarted(QWebEngineUrlRequestJob *job)
+ void requestStarted(QWebEngineUrlRequestJob *job) override
{
QBuffer *buffer = new QBuffer(job);
buffer->setData(QByteArray(128 * 1024, ' ') +
@@ -782,7 +789,7 @@ void tst_QWebEngineProfile::customUserAgent()
QWebEnginePage page;
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.setHtml(QStringLiteral("<html><body>Hello world!</body></html>"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
// First test the user-agent is default
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), defaultUserAgent);
@@ -795,7 +802,7 @@ void tst_QWebEngineProfile::customUserAgent()
QWebEnginePage page2(&testProfile);
QSignalSpy loadFinishedSpy2(&page2, SIGNAL(loadFinished(bool)));
page2.setHtml(QStringLiteral("<html><body>Hello again!</body></html>"));
- QTRY_COMPARE(loadFinishedSpy2.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy2.size(), 1);
QCOMPARE(evaluateJavaScriptSync(&page2, QStringLiteral("navigator.userAgent")).toString(), testUserAgent);
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), defaultUserAgent);
@@ -809,7 +816,7 @@ void tst_QWebEngineProfile::httpAcceptLanguage()
QWebEnginePage page;
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.setHtml(QStringLiteral("<html><body>Hello world!</body></html>"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QStringList defaultLanguages = evaluateJavaScriptSync(&page, QStringLiteral("navigator.languages")).toStringList();
@@ -821,7 +828,7 @@ void tst_QWebEngineProfile::httpAcceptLanguage()
QWebEnginePage page2(&testProfile);
QSignalSpy loadFinishedSpy2(&page2, SIGNAL(loadFinished(bool)));
page2.setHtml(QStringLiteral("<html><body>Hello again!</body></html>"));
- QTRY_COMPARE(loadFinishedSpy2.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy2.size(), 1);
QCOMPARE(evaluateJavaScriptSync(&page2, QStringLiteral("navigator.languages")).toStringList(), QStringList(testLang));
// Test the old one wasn't affected
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.languages")).toStringList(), defaultLanguages);
@@ -833,12 +840,12 @@ void tst_QWebEngineProfile::httpAcceptLanguage()
void tst_QWebEngineProfile::downloadItem()
{
- qRegisterMetaType<QWebEngineDownloadItem *>();
+ qRegisterMetaType<QWebEngineDownloadRequest *>();
QWebEngineProfile testProfile;
QWebEnginePage page(&testProfile);
- QSignalSpy downloadSpy(&testProfile, SIGNAL(downloadRequested(QWebEngineDownloadItem *)));
+ QSignalSpy downloadSpy(&testProfile, SIGNAL(downloadRequested(QWebEngineDownloadRequest *)));
page.load(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
- QTRY_COMPARE(downloadSpy.count(), 1);
+ QTRY_COMPARE(downloadSpy.size(), 1);
}
void tst_QWebEngineProfile::changePersistentPath()
@@ -846,12 +853,12 @@ void tst_QWebEngineProfile::changePersistentPath()
TestServer server;
QVERIFY(server.start());
- AutoDir dataDir1(QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + QStringLiteral("/QtWebEngine/Test"));
- AutoDir dataDir2(QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + QStringLiteral("/QtWebEngine/Test2"));
+ AutoDir dataDir1(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
+ + QStringLiteral("/QtWebEngine/changePersistentPath1"));
+ AutoDir dataDir2(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
+ + QStringLiteral("/QtWebEngine/changePersistentPath2"));
- QWebEngineProfile testProfile(QStringLiteral("Test"));
+ QWebEngineProfile testProfile(QStringLiteral("changePersistentPath1"));
QCOMPARE(testProfile.persistentStoragePath(), dataDir1.path());
// Make sure the profile has been used:
@@ -872,13 +879,13 @@ void tst_QWebEngineProfile::changeHttpUserAgent()
TestServer server;
QVERIFY(server.start());
- QVector<QByteArray> userAgents;
+ QList<QByteArray> userAgents;
connect(&server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
if (rr->requestPath() == "/hedgehog.html")
userAgents.push_back(rr->requestHeader(QByteArrayLiteral("user-agent")));
});
- QWebEngineProfile profile(QStringLiteral("Test"));
+ QWebEngineProfile profile(QStringLiteral("changeHttpUserAgent"));
std::unique_ptr<QWebEnginePage> page;
page.reset(new QWebEnginePage(&profile));
QVERIFY(loadSync(page.get(), server.url("/hedgehog.html")));
@@ -899,13 +906,13 @@ void tst_QWebEngineProfile::changeHttpAcceptLanguage()
TestServer server;
QVERIFY(server.start());
- QVector<QByteArray> languages;
+ QList<QByteArray> languages;
connect(&server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
if (rr->requestPath() == "/hedgehog.html")
languages.push_back(rr->requestHeader(QByteArrayLiteral("accept-language")));
});
- QWebEngineProfile profile(QStringLiteral("Test"));
+ QWebEngineProfile profile(QStringLiteral("changeHttpAcceptLanguage"));
std::unique_ptr<QWebEnginePage> page;
page.reset(new QWebEnginePage(&profile));
QVERIFY(loadSync(page.get(), server.url("/hedgehog.html")));
@@ -921,25 +928,6 @@ void tst_QWebEngineProfile::changeHttpAcceptLanguage()
QVERIFY(server.stop());
}
-void tst_QWebEngineProfile::changeUseForGlobalCertificateVerification()
-{
- TestServer server;
- QVERIFY(server.start());
-
- // Check that we don't crash
-
- QWebEngineProfile profile(QStringLiteral("Test"));
- std::unique_ptr<QWebEnginePage> page;
- page.reset(new QWebEnginePage(&profile));
- QVERIFY(loadSync(page.get(), server.url("/hedgehog.html")));
- page.reset();
- profile.setUseForGlobalCertificateVerification(true);
- page.reset(new QWebEnginePage(&profile));
- QVERIFY(loadSync(page.get(), server.url("/hedgehog.html")));
- // Don't check for error: there can be disconnects during GET hedgehog.png.
- (void)server.stop();
-}
-
void tst_QWebEngineProfile::changePersistentCookiesPolicy()
{
TestServer server;
@@ -947,7 +935,7 @@ void tst_QWebEngineProfile::changePersistentCookiesPolicy()
AutoDir dataDir("./tst_QWebEngineProfile_dataDir");
- QWebEngineProfile profile(QStringLiteral("Test"));
+ QWebEngineProfile profile(QStringLiteral("changePersistentCookiesPolicy"));
QWebEnginePage page(&profile);
profile.setPersistentStoragePath(dataDir.path());
@@ -983,29 +971,29 @@ void tst_QWebEngineProfile::initiator()
QWebEnginePage page(&profile, nullptr);
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.load(QUrl("about:blank"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
loadFinishedSpy.clear();
// about:blank has a unique origin, so initiator should be QUrl("null")
evaluateJavaScriptSync(&page, "window.location = 'foo:bar'");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
loadFinishedSpy.clear();
QCOMPARE(handler.initiator, QUrl("null"));
page.setHtml("", QUrl("http://test:123/foo%20bar"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
loadFinishedSpy.clear();
// baseUrl determines the origin, so QUrl("http://test:123")
evaluateJavaScriptSync(&page, "window.location = 'foo:bar'");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 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"));
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 10000);
QCOMPARE(handler.initiator, QUrl());
}
@@ -1021,7 +1009,7 @@ void tst_QWebEngineProfile::badDeleteOrder()
QSignalSpy spyLoadFinished(page, SIGNAL(loadFinished(bool)));
page->setHtml(QStringLiteral("<html><body><h1>Badly handled page!</h1></body></html>"));
- QTRY_COMPARE(spyLoadFinished.count(), 1);
+ QTRY_COMPARE(spyLoadFinished.size(), 1);
delete profile;
delete view;
@@ -1037,7 +1025,7 @@ void tst_QWebEngineProfile::qtbug_71895()
view.page()->profile()->setHttpCacheType(QWebEngineProfile::NoCache);
view.page()->profile()->cookieStore()->deleteAllCookies();
view.page()->profile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
- bool gotSignal = loadSpy.count() || loadSpy.wait(20000);
+ bool gotSignal = loadSpy.size() || loadSpy.wait(20000);
if (!gotSignal)
QSKIP("Couldn't load page from network, skipping test.");
}
diff --git a/tests/auto/widgets/qwebenginescript/CMakeLists.txt b/tests/auto/widgets/qwebenginescript/CMakeLists.txt
new file mode 100644
index 000000000..d0d499b84
--- /dev/null
+++ b/tests/auto/widgets/qwebenginescript/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebenginescript
+ SOURCES
+ tst_qwebenginescript.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+set(tst_qwebenginescript_resource_files
+ "resources/test_iframe_inner.html"
+ "resources/test_iframe_main.html"
+ "resources/test_iframe_outer.html"
+ "resources/test_window_open.html"
+ "resources/title_a.html"
+ "resources/title_b.html"
+ "resources/webChannelWithBadString.html"
+)
+
+qt_internal_add_resource(tst_qwebenginescript "tst_qwebenginescript"
+ PREFIX
+ "/"
+ FILES
+ ${tst_qwebenginescript_resource_files}
+)
diff --git a/tests/auto/widgets/qwebenginescript/qwebenginescript.pro b/tests/auto/widgets/qwebenginescript/qwebenginescript.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/qwebenginescript/qwebenginescript.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/qwebenginescript/resources/test_window_open.html b/tests/auto/widgets/qwebenginescript/resources/test_window_open.html
index 3f72d176d..3ceafc49d 100644
--- a/tests/auto/widgets/qwebenginescript/resources/test_window_open.html
+++ b/tests/auto/widgets/qwebenginescript/resources/test_window_open.html
@@ -3,7 +3,7 @@
<head>
<title>window.open</title>
<script>
- window.open("qrc:/resource/test_iframe_main.html", "iframe_main");
+ window.open("qrc:/resources/test_iframe_main.html", "iframe_main");
</script>
</head>
<body></body>
diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
index 32384aec2..9ba13589f 100644
--- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
+++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
@@ -25,7 +25,7 @@
#include <qwebenginescriptcollection.h>
#include <qwebenginesettings.h>
#include <qwebengineview.h>
-#include "../util.h"
+#include <util.h>
#if QT_CONFIG(webengine_webchannel)
#include <QWebChannel>
#endif
@@ -40,6 +40,8 @@ static bool verifyOrder(QStringList orderList)
"Deferred"
};
+ if (orderList.size() != 5)
+ return false;
if (orderList.at(4) == "load (timeout)") {
if (orderList.at(3) != "Deferred")
return false;
@@ -68,10 +70,13 @@ private Q_SLOTS:
void webChannelWithExistingQtObject();
void navigation();
void webChannelWithBadString();
+ void webChannelWithJavaScriptDisabled();
#endif
void noTransportWithoutWebChannel();
void scriptsInNestedIframes();
void matchQrcUrl();
+ void injectionOrder();
+ void reloadWithSubframes();
};
void tst_QWebEngineScript::domEditing()
@@ -180,7 +185,7 @@ void tst_QWebEngineScript::loadEvents()
// Single frame / setHtml
page.setHtml(QStringLiteral("<!DOCTYPE html><html><head><title>mr</title></head><body></body></html>"));
- QTRY_COMPARE_WITH_TIMEOUT(page.spy.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(page.spy.size(), 1, 20000);
QVERIFY(page.spy.takeFirst().value(0).toBool());
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::MainWorld).toStringList()));
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList()));
@@ -188,14 +193,14 @@ void tst_QWebEngineScript::loadEvents()
// After discard
page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
- QTRY_COMPARE_WITH_TIMEOUT(page.spy.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(page.spy.size(), 1, 20000);
QVERIFY(page.spy.takeFirst().value(0).toBool());
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::MainWorld).toStringList()));
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList()));
// Multiple frames
page.load(QUrl("qrc:/resources/test_iframe_main.html"));
- QTRY_COMPARE_WITH_TIMEOUT(page.spy.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(page.spy.size(), 1, 20000);
QVERIFY(page.spy.takeFirst().value(0).toBool());
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::MainWorld).toStringList()));
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList()));
@@ -206,7 +211,7 @@ void tst_QWebEngineScript::loadEvents()
// Cross-process navigation
page.load(QUrl("chrome://gpu"));
- QTRY_COMPARE_WITH_TIMEOUT(page.spy.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(page.spy.size(), 1, 20000);
QVERIFY(page.spy.takeFirst().value(0).toBool());
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::MainWorld).toStringList()));
QVERIFY(verifyOrder(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList()));
@@ -214,9 +219,9 @@ void tst_QWebEngineScript::loadEvents()
// Using window.open from JS
QVERIFY(profile.pages.size() == 1);
page.load(QUrl("qrc:/resources/test_window_open.html"));
- QTRY_COMPARE(profile.pages.size(), 2);
- QTRY_COMPARE(profile.pages.front().spy.count(), 1);
- QTRY_COMPARE(profile.pages.back().spy.count(), 1);
+ QTRY_COMPARE(profile.pages.size(), 2u);
+ QTRY_COMPARE(profile.pages.front().spy.size(), 1);
+ QTRY_COMPARE(profile.pages.back().spy.size(), 1);
QVERIFY(verifyOrder(profile.pages.front().eval("window.log", QWebEngineScript::MainWorld).toStringList()));
QVERIFY(verifyOrder(profile.pages.front().eval("window.log", QWebEngineScript::ApplicationWorld).toStringList()));
QVERIFY(verifyOrder(profile.pages.back().eval("window.log", QWebEngineScript::MainWorld).toStringList()));
@@ -267,7 +272,7 @@ void tst_QWebEngineScript::scriptDisabled()
page.scripts().insert(script);
page.load(QUrl("about:blank"));
QSignalSpy spy(&page, &QWebEnginePage::loadFinished);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().value(0).toBool(), true);
// MainWorld scripts are disabled by the setting...
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "foo", QWebEngineScript::MainWorld), QVariant());
@@ -276,7 +281,7 @@ void tst_QWebEngineScript::scriptDisabled()
page.scripts().clear();
page.scripts().insert(script);
page.load(QUrl("about:blank"));
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().value(0).toBool(), true);
// ...but ApplicationWorld scripts should still work
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "foo", QWebEngineScript::MainWorld), QVariant());
@@ -294,7 +299,7 @@ void tst_QWebEngineScript::viewSource()
page.scripts().insert(script);
page.load(QUrl("view-source:about:blank"));
QSignalSpy spy(&page, &QWebEnginePage::loadFinished);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
QCOMPARE(spy.takeFirst().value(0).toBool(), true);
QCOMPARE(evaluateJavaScriptSync(&page, "foo"), QVariant(42));
}
@@ -320,8 +325,8 @@ void tst_QWebEngineScript::scriptModifications()
QVERIFY(spyFinished.wait());
QCOMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS")));
QVERIFY(page.scripts().count() == 1);
- QWebEngineScript s = page.scripts().findScript(QStringLiteral("String1"));
- QVERIFY(page.scripts().remove(s));
+ QList<QWebEngineScript> s = page.scripts().find(QStringLiteral("String1"));
+ QVERIFY(page.scripts().remove(s.first()));
QVERIFY(page.scripts().count() == 0);
}
@@ -413,7 +418,7 @@ void tst_QWebEngineScript::webChannel()
QCOMPARE(testObject.text(), QStringLiteral("test"));
if (worldId != QWebEngineScript::MainWorld)
- QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid));
+ QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant());
}
#endif
void tst_QWebEngineScript::noTransportWithoutWebChannel()
@@ -421,11 +426,11 @@ void tst_QWebEngineScript::noTransportWithoutWebChannel()
QWebEnginePage page;
page.setHtml(QStringLiteral("<html><body></body></html>"));
- QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid));
+ QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant());
page.triggerAction(QWebEnginePage::Reload);
QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
QVERIFY(spyFinished.wait());
- QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid));
+ QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant());
}
void tst_QWebEngineScript::scriptsInNestedIframes()
@@ -453,7 +458,7 @@ void tst_QWebEngineScript::scriptsInNestedIframes()
QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
page.load(QUrl("qrc:/resources/test_iframe_main.html"));
view.show();
- QVERIFY(spyFinished.wait());
+ QTRY_VERIFY_WITH_TIMEOUT(spyFinished.size() > 0, 20000);
// Check that main frame has modified content.
QCOMPARE(
@@ -486,9 +491,9 @@ void tst_QWebEngineScript::webChannelResettingAndUnsetting()
// There should be no webChannelTransport yet.
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::MainWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::ApplicationWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
QWebChannel channel;
page.setWebChannel(&channel, QWebEngineScript::MainWorld);
@@ -497,13 +502,13 @@ void tst_QWebEngineScript::webChannelResettingAndUnsetting()
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::MainWorld),
QVariant(QVariantMap()));
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::ApplicationWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
page.setWebChannel(&channel, QWebEngineScript::ApplicationWorld);
// Now it should have moved to ApplicationWorld.
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::MainWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::ApplicationWorld),
QVariant(QVariantMap()));
@@ -511,9 +516,9 @@ void tst_QWebEngineScript::webChannelResettingAndUnsetting()
// And now it should be gone again.
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::MainWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "qt.webChannelTransport", QWebEngineScript::ApplicationWorld),
- QVariant(QVariant::Invalid));
+ QVariant());
}
void tst_QWebEngineScript::webChannelWithExistingQtObject()
@@ -521,7 +526,7 @@ void tst_QWebEngineScript::webChannelWithExistingQtObject()
QWebEnginePage page;
evaluateJavaScriptSync(&page, "qt = 42");
- QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid));
+ QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant());
QWebChannel channel;
page.setWebChannel(&channel);
@@ -553,22 +558,22 @@ void tst_QWebEngineScript::navigation()
QString url1 = QStringLiteral("about:blank");
page.setUrl(url1);
- QTRY_COMPARE(spyTextChanged.count(), 1);
+ QTRY_COMPARE(spyTextChanged.size(), 1);
QCOMPARE(testObject.text(), url1);
QString url2 = QStringLiteral("chrome://gpu/");
page.setUrl(url2);
- QTRY_COMPARE(spyTextChanged.count(), 2);
+ QTRY_COMPARE(spyTextChanged.size(), 2);
QCOMPARE(testObject.text(), url2);
QString url3 = QStringLiteral("qrc:/resources/test_iframe_main.html");
page.setUrl(url3);
- QTRY_COMPARE(spyTextChanged.count(), 3);
+ QTRY_COMPARE(spyTextChanged.size(), 3);
QCOMPARE(testObject.text(), url3);
page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
page.setUrl(url1);
- QTRY_COMPARE(spyTextChanged.count(), 4);
+ QTRY_COMPARE(spyTextChanged.size(), 4);
QCOMPARE(testObject.text(), url1);
}
@@ -589,6 +594,36 @@ void tst_QWebEngineScript::webChannelWithBadString()
QChar data(0xd800);
QCOMPARE(host.text(), data);
}
+
+void tst_QWebEngineScript::webChannelWithJavaScriptDisabled()
+{
+ QWebEnginePage page;
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+ // JavaScript disabled in main world
+ page.settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
+
+ TestObject testObject;
+ QScopedPointer<QWebChannel> channel(new QWebChannel(this));
+ channel->registerObject(QStringLiteral("object"), &testObject);
+ page.setWebChannel(channel.data(), QWebEngineScript::ApplicationWorld);
+
+ QWebEngineScript script = webChannelScript();
+ script.setWorldId(QWebEngineScript::ApplicationWorld);
+ page.scripts().insert(script);
+
+ page.setHtml(QStringLiteral("<html><body></body></html>"));
+ QVERIFY(spyFinished.wait());
+
+ QSignalSpy spyTextChanged(&testObject, &TestObject::textChanged);
+ page.runJavaScript(QLatin1String(
+ "new QWebChannel(qt.webChannelTransport,"
+ " function(channel) {"
+ " channel.objects.object.text = 'test';"
+ " }"
+ ");"), QWebEngineScript::ApplicationWorld);
+ QVERIFY(spyTextChanged.wait());
+ QCOMPARE(testObject.text(), QStringLiteral("test"));
+}
#endif
void tst_QWebEngineScript::matchQrcUrl()
@@ -612,6 +647,86 @@ document.title = 'New title';
QCOMPARE(page.title(), "New title");
}
+// Add many scripts and check order of execution.
+void tst_QWebEngineScript::injectionOrder()
+{
+ QWebEngineProfile profile;
+ class Page : public QWebEnginePage
+ {
+ public:
+ Page(QWebEngineProfile *profile) : QWebEnginePage(profile) {}
+ QVector<QString> log;
+
+ protected:
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel, const QString &message, int,
+ const QString &) override
+ {
+ log.append(message);
+ }
+ } page(&profile);
+ QWebEngineScript::InjectionPoint points[] = {
+ QWebEngineScript::DocumentCreation,
+ QWebEngineScript::DocumentReady,
+ QWebEngineScript::Deferred,
+ };
+ int nPoints = 3;
+ int nCollections = 2;
+ int nScripts = 5;
+
+ QVector<QString> expected;
+ for (int iPoint = 0; iPoint != nPoints; ++iPoint) {
+ for (int iCollection = 0; iCollection != nCollections; ++iCollection) {
+ for (int iScript = 0; iScript != nScripts; ++iScript) {
+ QWebEngineScript script;
+ script.setName(QString("%1%2%3").arg(iPoint).arg(iCollection).arg(iScript));
+ expected.append(script.name());
+ script.setInjectionPoint(points[iPoint]);
+ script.setWorldId(QWebEngineScript::MainWorld);
+ script.setSourceCode(QStringLiteral("console.error('%1');").arg(script.name()));
+ if (iCollection == 0)
+ profile.scripts()->insert(script);
+ else
+ page.scripts().insert(script);
+ }
+ }
+ }
+
+ page.load(QUrl("qrc:/resources/test_iframe_inner.html"));
+ QTRY_COMPARE(page.log, expected);
+}
+
+void tst_QWebEngineScript::reloadWithSubframes()
+{
+ class Page : public QWebEnginePage
+ {
+ public:
+ Page() : QWebEnginePage() {}
+ QVector<QString> log;
+
+ protected:
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel, const QString &message, int,
+ const QString &) override
+ {
+ log.append(message);
+ }
+ } page;
+
+ QWebEngineScript s;
+ s.setInjectionPoint(QWebEngineScript::DocumentCreation);
+ s.setSourceCode(QStringLiteral("console.log('Hello');"));
+ page.scripts().insert(s);
+
+ page.setHtml(QStringLiteral("<body>"
+ " <h1>Test scripts working on reload </h1>"
+ " <iframe src='about://blank'>"
+ " </iframe>"
+ "</body>"));
+ QTRY_COMPARE(page.log.size(), 1);
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(page.log.size(), 2);
+}
+
QTEST_MAIN(tst_QWebEngineScript)
#include "tst_qwebenginescript.moc"
diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc
deleted file mode 100644
index 3290cb588..000000000
--- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>resources/test_iframe_main.html</file>
- <file>resources/test_iframe_outer.html</file>
- <file>resources/test_iframe_inner.html</file>
- <file>resources/test_window_open.html</file>
- <file>resources/title_a.html</file>
- <file>resources/title_b.html</file>
- <file>resources/webChannelWithBadString.html</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro b/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro
deleted file mode 100644
index 70786e70f..000000000
--- a/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-include(../tests.pri)
-QT *= core-private gui-private
diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
deleted file mode 100644
index a09901e69..000000000
--- a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- Copyright (C) 2015 The Qt Company Ltd.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "../util.h"
-
-#include <QtTest/QtTest>
-
-#include <qwebenginepage.h>
-#include <qwebengineprofile.h>
-#include <qwebenginesettings.h>
-
-#include <QtGui/qclipboard.h>
-#include <QtGui/qguiapplication.h>
-
-class tst_QWebEngineSettings: public QObject {
- Q_OBJECT
-
-private Q_SLOTS:
- void resetAttributes();
- void defaultFontFamily_data();
- void defaultFontFamily();
- void javascriptClipboard_data();
- void javascriptClipboard();
- void setInAcceptNavigationRequest();
-};
-
-void tst_QWebEngineSettings::resetAttributes()
-{
- QWebEngineProfile profile;
- QWebEngineSettings *settings = profile.settings();
-
- // Attribute
- bool defaultValue = settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled);
- settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, !defaultValue);
- QCOMPARE(!defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled));
- settings->resetAttribute(QWebEngineSettings::FullScreenSupportEnabled);
- QCOMPARE(defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled));
-
- // Font family
- QString defaultFamily = settings->fontFamily(QWebEngineSettings::StandardFont);
- QString newFontFamily("PugDog");
- settings->setFontFamily(QWebEngineSettings::StandardFont, newFontFamily);
- QCOMPARE(newFontFamily, settings->fontFamily(QWebEngineSettings::StandardFont));
- settings->resetFontFamily(QWebEngineSettings::StandardFont);
- QCOMPARE(defaultFamily, settings->fontFamily(QWebEngineSettings::StandardFont));
-
- // Font size
- int defaultSize = settings->fontSize(QWebEngineSettings::MinimumFontSize);
- int newSize = defaultSize + 10;
- settings->setFontSize(QWebEngineSettings::MinimumFontSize, newSize);
- QCOMPARE(newSize, settings->fontSize(QWebEngineSettings::MinimumFontSize));
- settings->resetFontSize(QWebEngineSettings::MinimumFontSize);
- QCOMPARE(defaultSize, settings->fontSize(QWebEngineSettings::MinimumFontSize));
-}
-
-void tst_QWebEngineSettings::defaultFontFamily_data()
-{
- QTest::addColumn<int>("fontFamily");
-
- QTest::newRow("StandardFont") << static_cast<int>(QWebEngineSettings::StandardFont);
- QTest::newRow("FixedFont") << static_cast<int>(QWebEngineSettings::FixedFont);
- QTest::newRow("SerifFont") << static_cast<int>(QWebEngineSettings::SerifFont);
- QTest::newRow("SansSerifFont") << static_cast<int>(QWebEngineSettings::SansSerifFont);
- QTest::newRow("CursiveFont") << static_cast<int>(QWebEngineSettings::CursiveFont);
- QTest::newRow("FantasyFont") << static_cast<int>(QWebEngineSettings::FantasyFont);
-}
-
-void tst_QWebEngineSettings::defaultFontFamily()
-{
- QWebEngineProfile profile;
- QWebEngineSettings *settings = profile.settings();
-
- QFETCH(int, fontFamily);
- QVERIFY(!settings->fontFamily(static_cast<QWebEngineSettings::FontFamily>(fontFamily)).isEmpty());
-}
-
-void tst_QWebEngineSettings::javascriptClipboard_data()
-{
- QTest::addColumn<bool>("javascriptCanAccessClipboard");
- QTest::addColumn<bool>("javascriptCanPaste");
- QTest::addColumn<bool>("copyResult");
- QTest::addColumn<bool>("pasteResult");
-
- QTest::newRow("default") << false << false << false << false;
- QTest::newRow("canCopy") << true << false << true << false;
- // paste command requires both permissions
- QTest::newRow("canPaste") << false << true << false << false;
- QTest::newRow("canCopyAndPaste") << true << true << true << true;
-}
-
-void tst_QWebEngineSettings::javascriptClipboard()
-{
- QFETCH(bool, javascriptCanAccessClipboard);
- QFETCH(bool, javascriptCanPaste);
- QFETCH(bool, copyResult);
- QFETCH(bool, pasteResult);
-
- QWebEnginePage page;
-
- // check defaults
- QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard),
- false);
- QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste), false);
-
- // check accessors
- page.settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard,
- javascriptCanAccessClipboard);
- page.settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste,
- javascriptCanPaste);
- QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard),
- javascriptCanAccessClipboard);
- QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste),
- javascriptCanPaste);
-
- QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
- page.setHtml("<html><body>"
- "<input type='text' value='OriginalText' id='myInput'/>"
- "</body></html>");
- QVERIFY(loadFinishedSpy.wait());
-
- // make sure that 'OriginalText' is selected
- evaluateJavaScriptSync(&page, "document.getElementById('myInput').select()");
- QCOMPARE(evaluateJavaScriptSync(&page, "window.getSelection().toString()").toString(),
- QStringLiteral("OriginalText"));
-
- // Check that the actual settings work by the
- // - return value of queryCommandEnabled and
- // - return value of execCommand
- // - comparing the clipboard / input field
- QGuiApplication::clipboard()->clear();
- QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('copy')").toBool(),
- copyResult);
- QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('copy')").toBool(), copyResult);
- QTRY_COMPARE(QApplication::clipboard()->text(),
- (copyResult ? QString("OriginalText") : QString()));
-
-
- QGuiApplication::clipboard()->setText("AnotherText");
- QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('paste')").toBool(),
- pasteResult);
- QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('paste')").toBool(), pasteResult);
- QCOMPARE(evaluateJavaScriptSync(&page, "document.getElementById('myInput').value").toString(),
- (pasteResult ? QString("AnotherText") : QString("OriginalText")));
-}
-
-class NavigationRequestOverride : public QWebEnginePage
-{
-protected:
- virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
- {
- Q_UNUSED(type);
-
- if (isMainFrame && url.scheme().startsWith("data"))
- settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
- // TODO: note this setting is flaky, consider settings().commit()
- return true;
- }
-};
-
-void tst_QWebEngineSettings::setInAcceptNavigationRequest()
-{
- NavigationRequestOverride page;
- QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
- QVERIFY(!page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled));
-
- page.load(QUrl("about:blank"));
- QVERIFY(loadFinishedSpy.wait());
- QVERIFY(!page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled));
-
- page.setHtml("<html><body>"
- "<script>document.write('PASS')</script>"
- "<noscript>FAIL</noscript>"
- "</body></html>");
- QVERIFY(loadFinishedSpy.wait());
- QVERIFY(page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled));
- QCOMPARE(toPlainTextSync(&page), QStringLiteral("PASS"));
-}
-
-QTEST_MAIN(tst_QWebEngineSettings)
-
-#include "tst_qwebenginesettings.moc"
diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST
index 266f08886..26f2da4bb 100644
--- a/tests/auto/widgets/qwebengineview/BLACKLIST
+++ b/tests/auto/widgets/qwebengineview/BLACKLIST
@@ -1,8 +1,12 @@
-[microFocusCoordinates]
-osx
-
-[textSelectionOutOfInputField]
+[mixLangLocale:eu_ES]
*
-[visibilityState3]
+[navigateOnDrop:file]
+windows
+
+[navigateOnDrop:file_no_navigate]
windows
+
+[horizontalScrollbarTest]
+macos
+rhel # flaky
diff --git a/tests/auto/widgets/qwebengineview/CMakeLists.txt b/tests/auto/widgets/qwebengineview/CMakeLists.txt
new file mode 100644
index 000000000..9583184d0
--- /dev/null
+++ b/tests/auto/widgets/qwebengineview/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebengineview
+ SOURCES
+ tst_qwebengineview.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Qt::WebEngineCorePrivate
+ Qt::GuiPrivate
+ Qt::QuickWidgets
+ Qt::TestPrivate
+ Test::Util
+)
+
+set(tst_qwebengineview_resource_files
+ "resources/dummy.html"
+ "resources/frame_a.html"
+ "resources/image2.png"
+ "resources/index.html"
+ "resources/input_types.html"
+ "resources/keyboardEvents.html"
+ "resources/scrolltest_page.html"
+)
+
+qt_internal_add_resource(tst_qwebengineview "tst_qwebengineview"
+ PREFIX
+ "/"
+ FILES
+ ${tst_qwebengineview_resource_files}
+)
diff --git a/tests/auto/widgets/qwebengineview/qwebengineview.pro b/tests/auto/widgets/qwebengineview/qwebengineview.pro
deleted file mode 100644
index d91c0074b..000000000
--- a/tests/auto/widgets/qwebengineview/qwebengineview.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-include(../tests.pri)
-QT *= gui-private
diff --git a/tests/auto/widgets/qwebengineview/resources/dummy.html b/tests/auto/widgets/qwebengineview/resources/dummy.html
new file mode 100644
index 000000000..f5ba1963a
--- /dev/null
+++ b/tests/auto/widgets/qwebengineview/resources/dummy.html
@@ -0,0 +1,6 @@
+<html><head>
+<title>Dummy simple page without real content</title>
+<link rel='icon' href='qrc:///resources/image2.png'/>
+</head><body>
+<a>This is test content</a>
+</body></html>
diff --git a/tests/auto/widgets/resources/test.swf b/tests/auto/widgets/qwebengineview/resources/test.swf
index 895298271..895298271 100644
--- a/tests/auto/widgets/resources/test.swf
+++ b/tests/auto/widgets/qwebengineview/resources/test.swf
Binary files differ
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 5e16361c5..f4ed06e14 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -19,35 +19,42 @@
Boston, MA 02110-1301, USA.
*/
-#include <qtest.h>
-#include "../util.h"
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+#include <QtWebEngineCore/private/qtwebenginecore-config_p.h>
+#include <qtest.h>
+#include <util.h>
#include <private/qinputmethod_p.h>
#include <qpainter.h>
#include <qpagelayout.h>
-#include <qpa/qplatforminputcontext.h>
#include <qwebengineview.h>
#include <qwebenginepage.h>
#include <qwebenginesettings.h>
-#include <qnetworkrequest.h>
+#include <qaction.h>
#include <qdiriterator.h>
+#include <qnetworkrequest.h>
#include <qstackedlayout.h>
#include <qtemporarydir.h>
#include <QClipboard>
#include <QCompleter>
+#include <QDropEvent>
#include <QLabel>
#include <QLineEdit>
+#include <QListView>
#include <QHBoxLayout>
#include <QMenu>
+#include <QMimeData>
#include <QQuickItem>
#include <QQuickWidget>
#include <QtWebEngineCore/qwebenginehttprequest.h>
+#include <QScopeGuard>
+#include <QStringListModel>
#include <QTcpServer>
#include <QTcpSocket>
#include <QStyle>
-#include <QtWidgets/qaction.h>
#include <QWebEngineProfile>
#include <QtCore/qregularexpression.h>
+#include <QtTest/private/qemulationdetector_p.h>
#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \
QVERIFY(actual == (expect | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu));
@@ -60,44 +67,6 @@ do { \
QCOMPARE((__expr), __expected); \
} while (0)
-static QTouchDevice* s_touchDevice = nullptr;
-
-static QPoint elementCenter(QWebEnginePage *page, const QString &id)
-{
- const QString jsCode(
- "(function(){"
- " var elem = document.getElementById('" + id + "');"
- " var rect = elem.getBoundingClientRect();"
- " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];"
- "})()");
- QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList();
-
- if (rectList.count() != 2) {
- qWarning("elementCenter failed.");
- return QPoint();
- }
-
- return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt());
-}
-
-static QRect elementGeometry(QWebEnginePage *page, const QString &id)
-{
- const QString jsCode(
- "(function() {"
- " var elem = document.getElementById('" + id + "');"
- " var rect = elem.getBoundingClientRect();"
- " return [rect.left, rect.top, rect.right, rect.bottom];"
- "})()");
- QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList();
-
- if (coords.count() != 4) {
- qWarning("elementGeometry faield.");
- return QRect();
- }
-
- return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt());
-}
-
QT_BEGIN_NAMESPACE
namespace QTest {
int Q_TESTLIB_EXPORT defaultMouseDelay();
@@ -106,7 +75,8 @@ namespace QTest {
{
QTest::qWait(QTest::defaultMouseDelay());
lastMouseTimestamp += QTest::defaultMouseDelay();
- QMouseEvent me(type, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ QMouseEvent me(type, pos, widget->mapToGlobal(pos), Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
me.setTimestamp(++lastMouseTimestamp);
QSpontaneKeyEvent::setSpontaneous(&me);
qApp->sendEvent(widget, &me);
@@ -142,6 +112,7 @@ private Q_SLOTS:
void changePage();
void reusePage_data();
void reusePage();
+ void setLoadedPage();
void microFocusCoordinates();
void focusInputTypes();
void unhandledKeyEventPropagation();
@@ -162,14 +133,13 @@ private Q_SLOTS:
void doNotBreakLayout();
void changeLocale();
+ void mixLangLocale_data();
+ void mixLangLocale();
void inputMethodsTextFormat_data();
void inputMethodsTextFormat();
void keyboardEvents();
void keyboardFocusAfterPopup();
void mouseClick();
- void touchTap();
- void touchTapAndHold();
- void touchTapAndHoldCancelled();
void postData();
void inputFieldOverridesShortcuts();
@@ -188,7 +158,7 @@ private Q_SLOTS:
void mouseLeave();
-#ifndef QT_NO_CLIPBOARD
+#if QT_CONFIG(clipboard)
void globalMouseSelection();
#endif
void noContextMenu();
@@ -202,6 +172,7 @@ private Q_SLOTS:
void jsKeyboardEvent_data();
void jsKeyboardEvent();
void deletePage();
+ void autoDeleteOnExternalPageDelete();
void closeOpenerTab();
void switchPage();
void setPageDeletesImplicitPage();
@@ -210,13 +181,20 @@ private Q_SLOTS:
void setPagePreservesExplicitPage();
void setViewPreservesExplicitPage();
void closeDiscardsPage();
+ void loadAfterRendererCrashed();
+ void inspectElement();
+ void navigateOnDrop_data();
+ void navigateOnDrop();
+ void emptyUriListOnDrop();
+ void datalist();
+ void longKeyEventText();
+ void pageWithPaintListeners();
};
// This will be called before the first test function is executed.
// It is only called once.
void tst_QWebEngineView::initTestCase()
{
- s_touchDevice = QTest::createTouchDevice();
}
// This will be called after the last test function is executed.
@@ -233,6 +211,96 @@ void tst_QWebEngineView::init()
// This will be called after every test function.
void tst_QWebEngineView::cleanup()
{
+ QTRY_COMPARE(QApplication::topLevelWidgets().size(), 0);
+}
+
+class PageWithPaintListeners : public QWebEnginePage
+{
+ Q_OBJECT
+public:
+ PageWithPaintListeners(QObject *parent = nullptr) : QWebEnginePage(parent)
+ {
+ addFirstContentfulPaintListener();
+ addLargestContentfulPaintListener();
+ }
+
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message,
+ int lineNumber, const QString &sourceID) override
+ {
+ Q_UNUSED(level)
+ Q_UNUSED(lineNumber)
+ Q_UNUSED(sourceID)
+ if (message.contains("firstContentfulPaint"))
+ emit firstContentfulPaint();
+ if (message.contains("largestContentfulPaint"))
+ emit largestContentfulPaint();
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver
+ void addFirstContentfulPaintListener()
+ {
+ QObject::connect(this, &QWebEnginePage::loadFinished, [this]() {
+ runJavaScript(QStringLiteral(
+ "new PerformanceObserver((entryList) => {"
+ " if (entryList.getEntriesByType('first-contentful-paint'))"
+ " console.log('firstContentfulPaint');"
+ "}).observe({type: 'paint', buffered: true});"));
+ });
+ }
+
+ void addLargestContentfulPaintListener()
+ {
+ QObject::connect(this, &QWebEnginePage::loadFinished, [this]() {
+ runJavaScript(QStringLiteral(
+ "new PerformanceObserver((entryList) => {"
+ " console.log('largestContentfulPaint');"
+ "}).observe({type: 'largest-contentful-paint', buffered: true});"));
+ });
+ }
+
+signals:
+ void firstContentfulPaint(); // https://web.dev/articles/fcp
+ void largestContentfulPaint(); // https://web.dev/articles/lcp
+};
+
+void tst_QWebEngineView::pageWithPaintListeners()
+{
+ PageWithPaintListeners page;
+
+ QSignalSpy firstContentfulPaintSpy(&page, &PageWithPaintListeners::firstContentfulPaint);
+ QSignalSpy largestContentfulPaintSpy(&page, &PageWithPaintListeners::largestContentfulPaint);
+
+ const QString empty =
+ QStringLiteral("<html><body style='width:100x;height:100px;'></body></html>");
+ const QString scrollBars =
+ QStringLiteral("<html><body style='width:1000px;height:1000px;'></body></html>");
+ const QString backgroundColor =
+ QStringLiteral("<html><body style='background-color:green'></body></html>");
+ const QString text = QStringLiteral("<html><body>text</body></html>");
+
+ QWebEngineView view;
+ view.setPage(&page);
+ view.resize(600, 600);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ page.setHtml(empty);
+ QTest::qWait(500); // empty page should not trigger
+ QVERIFY(firstContentfulPaintSpy.size() == 0);
+ QVERIFY(largestContentfulPaintSpy.size() == 0);
+
+ page.setHtml(backgroundColor);
+ QTRY_VERIFY(firstContentfulPaintSpy.size() == 1);
+
+ page.setHtml(text);
+ QTRY_VERIFY(firstContentfulPaintSpy.size() == 2);
+ QTRY_VERIFY(largestContentfulPaintSpy.size() == 1);
+
+#if !QT_CONFIG(webengine_embedded_build)
+ // Embedded builds have different scrollbars that are only painted on hover
+ page.setHtml(scrollBars);
+ QTRY_VERIFY(firstContentfulPaintSpy.size() == 3);
+#endif
}
void tst_QWebEngineView::renderHints()
@@ -331,64 +399,71 @@ void tst_QWebEngineView::changePage()
QSignalSpy pageFromLoadSpy(pageFrom.get(), &QWebEnginePage::loadFinished);
QSignalSpy pageFromIconLoadSpy(pageFrom.get(), &QWebEnginePage::iconChanged);
pageFrom->load(urlFrom);
- QTRY_COMPARE(pageFromLoadSpy.count(), 1);
+ QTRY_COMPARE(pageFromLoadSpy.size(), 1);
QCOMPARE(pageFromLoadSpy.last().value(0).toBool(), true);
if (!fromIsNullPage) {
- QTRY_COMPARE(pageFromIconLoadSpy.count(), 1);
+ QTRY_COMPARE(pageFromIconLoadSpy.size(), 1);
QVERIFY(!pageFromIconLoadSpy.last().value(0).isNull());
}
view->setPage(pageFrom.get());
+ QCOMPARE(view->page(), pageFrom.get());
+ QCOMPARE(QWebEngineView::forPage(pageFrom.get()), view.get());
- QTRY_COMPARE(spyUrl.count(), 1);
+ QTRY_COMPARE(spyUrl.size(), 1);
QCOMPARE(spyUrl.last().value(0).toUrl(), pageFrom->url());
- QTRY_COMPARE(spyTitle.count(), 1);
+ QTRY_COMPARE(spyTitle.size(), 1);
QCOMPARE(spyTitle.last().value(0).toString(), pageFrom->title());
- QTRY_COMPARE(spyIconUrl.count(), fromIsNullPage ? 0 : 1);
- QTRY_COMPARE(spyIcon.count(), fromIsNullPage ? 0 : 1);
+ QTRY_COMPARE(spyIconUrl.size(), fromIsNullPage ? 0 : 1);
+ QTRY_COMPARE(spyIcon.size(), fromIsNullPage ? 0 : 1);
if (!fromIsNullPage) {
QVERIFY(!pageFrom->iconUrl().isEmpty());
QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageFrom->iconUrl());
- QCOMPARE(spyIcon.last().value(0), QVariant::fromValue(pageFrom->icon()));
+ QCOMPARE(spyIcon.last().value(0).value<QIcon>().availableSizes(),
+ pageFrom->icon().availableSizes());
}
QScopedPointer<QWebEnginePage> pageTo(new QWebEnginePage);
QSignalSpy pageToLoadSpy(pageTo.get(), &QWebEnginePage::loadFinished);
QSignalSpy pageToIconLoadSpy(pageTo.get(), &QWebEnginePage::iconChanged);
pageTo->load(urlTo);
- QTRY_COMPARE(pageToLoadSpy.count(), 1);
+ QTRY_COMPARE(pageToLoadSpy.size(), 1);
QCOMPARE(pageToLoadSpy.last().value(0).toBool(), true);
if (!toIsNullPage) {
- QTRY_COMPARE(pageToIconLoadSpy.count(), 1);
+ QTRY_COMPARE(pageToIconLoadSpy.size(), 1);
QVERIFY(!pageToIconLoadSpy.last().value(0).isNull());
}
view->setPage(pageTo.get());
+ QCOMPARE(view->page(), pageTo.get());
+ QCOMPARE(QWebEngineView::forPage(pageTo.get()), view.get());
+ QCOMPARE(QWebEngineView::forPage(pageFrom.get()), nullptr);
- QTRY_COMPARE(spyUrl.count(), 2);
+ QTRY_COMPARE(spyUrl.size(), 2);
QCOMPARE(spyUrl.last().value(0).toUrl(), pageTo->url());
- QTRY_COMPARE(spyTitle.count(), 2);
+ QTRY_COMPARE(spyTitle.size(), 2);
QCOMPARE(spyTitle.last().value(0).toString(), pageTo->title());
bool iconIsSame = fromIsNullPage == toIsNullPage;
int iconChangeNotifyCount = fromIsNullPage ? (iconIsSame ? 0 : 1) : (iconIsSame ? 1 : 2);
- QTRY_COMPARE(spyIconUrl.count(), iconChangeNotifyCount);
- QTRY_COMPARE(spyIcon.count(), iconChangeNotifyCount);
+ QTRY_COMPARE(spyIconUrl.size(), iconChangeNotifyCount);
+ QTRY_COMPARE(spyIcon.size(), iconChangeNotifyCount);
QCOMPARE(pageFrom->iconUrl() == pageTo->iconUrl(), iconIsSame);
if (!iconIsSame) {
QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageTo->iconUrl());
- QCOMPARE(spyIcon.last().value(0), QVariant::fromValue(pageTo->icon()));
+ QCOMPARE(spyIcon.last().value(0).value<QIcon>().availableSizes(),
+ pageTo->icon().availableSizes());
}
// verify no emits on destroy with the same number of signals in spy
view.reset();
qApp->processEvents();
- QTRY_COMPARE(spyUrl.count(), 2);
- QTRY_COMPARE(spyTitle.count(), 2);
- QTRY_COMPARE(spyIconUrl.count(), iconChangeNotifyCount);
- QTRY_COMPARE(spyIcon.count(), iconChangeNotifyCount);
+ QTRY_COMPARE(spyUrl.size(), 2);
+ QTRY_COMPARE(spyTitle.size(), 2);
+ QTRY_COMPARE(spyIconUrl.size(), iconChangeNotifyCount);
+ QTRY_COMPARE(spyIcon.size(), iconChangeNotifyCount);
}
void tst_QWebEngineView::reusePage_data()
@@ -401,27 +476,31 @@ void tst_QWebEngineView::reusePage_data()
void tst_QWebEngineView::reusePage()
{
- if (!QDir(TESTS_SOURCE_DIR).exists())
- W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+ if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists())
+ W_QSKIP(QString("This test requires access to resources found in '%1'")
+ .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath())
+ .toLatin1()
+ .constData(),
+ SkipAll);
- QDir::setCurrent(TESTS_SOURCE_DIR);
+ QDir::setCurrent(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath());
QFETCH(QString, html);
QWebEngineView* view1 = new QWebEngineView;
QPointer<QWebEnginePage> page = new QWebEnginePage;
view1->setPage(page.data());
page.data()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
- page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
+ page->setHtml(html, QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()));
if (html.contains("</embed>")) {
// some reasonable time for the PluginStream to feed test.swf to flash and start painting
QSignalSpy spyFinished(view1, &QWebEngineView::loadFinished);
- QVERIFY(spyFinished.wait(2000));
+ QVERIFY(spyFinished.wait(20000));
}
view1->show();
QVERIFY(QTest::qWaitForWindowExposed(view1));
delete view1;
- QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view
+ QVERIFY(page != nullptr); // deleting view must not have deleted the page, since it's not a child of view
QWebEngineView *view2 = new QWebEngineView;
view2->setPage(page.data());
@@ -434,6 +513,23 @@ void tst_QWebEngineView::reusePage()
QDir::setCurrent(QApplication::applicationDirPath());
}
+void tst_QWebEngineView::setLoadedPage()
+{
+ // MEMO load page first to make sure that just simple attach to view would draw its content
+ QWebEnginePage page;
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+ page.setHtml(QString("<html><body bgcolor=\"%1\"></body></html>").arg(QColor(Qt::yellow).name()));
+ QTRY_VERIFY(loadSpy.size() == 1 && loadSpy.first().first().toBool());
+
+ QWebEngineView view;
+ view.resize(480, 320);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ view.setPage(&page);
+ QTRY_COMPARE(view.grab().toImage().pixelColor(QPoint(view.width() / 2, view.height() / 2)), Qt::yellow);
+}
+
// Class used in crashTests
class WebViewCrashTest : public QObject {
Q_OBJECT
@@ -508,7 +604,7 @@ void tst_QWebEngineView::microFocusCoordinates()
QVariant initialMicroFocus = webView.focusProxy()->inputMethodQuery(Qt::ImCursorRectangle);
evaluateJavaScriptSync(webView.page(), "window.scrollBy(0, 50)");
- QTRY_VERIFY(scrollSpy.count() > 0);
+ QTRY_VERIFY(scrollSpy.size() > 0);
QTRY_VERIFY(webView.focusProxy()->inputMethodQuery(Qt::ImCursorRectangle).isValid());
QVariant currentMicroFocus = webView.focusProxy()->inputMethodQuery(Qt::ImCursorRectangle);
@@ -518,8 +614,8 @@ void tst_QWebEngineView::microFocusCoordinates()
void tst_QWebEngineView::focusInputTypes()
{
- const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
- bool imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability);
+ const QPlatformInputContext *platformInputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
+ bool imeHasHiddenTextCapability = platformInputContext && platformInputContext->hasCapability(QPlatformInputContext::HiddenTextCapability);
QWebEngineView webView;
webView.resize(640, 480);
@@ -550,7 +646,8 @@ void tst_QWebEngineView::focusInputTypes()
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);
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
+ QTRY_COMPARE(platformInputContext->inputMethodAccepted(), imeHasHiddenTextCapability);
// 'tel' field
QPoint telInputCenter = elementCenter(webView.page(), "telInput");
@@ -589,7 +686,8 @@ void tst_QWebEngineView::focusInputTypes()
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);
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
+ QTRY_COMPARE(platformInputContext->inputMethodAccepted(), imeHasHiddenTextCapability);
// 'text' type
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textInputCenter);
@@ -603,7 +701,8 @@ void tst_QWebEngineView::focusInputTypes()
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);
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
+ QTRY_COMPARE(platformInputContext->inputMethodAccepted(), imeHasHiddenTextCapability);
// 'text area' field
QPoint textAreaCenter = elementCenter(webView.page(), "textArea");
@@ -616,10 +715,11 @@ void tst_QWebEngineView::focusInputTypes()
class KeyEventRecordingWidget : public QWidget {
public:
- QList<QKeyEvent> pressEvents;
- QList<QKeyEvent> releaseEvents;
- void keyPressEvent(QKeyEvent *e) override { pressEvents << *e; }
- void keyReleaseEvent(QKeyEvent *e) override { releaseEvents << *e; }
+ ~KeyEventRecordingWidget() { qDeleteAll(pressEvents); qDeleteAll(releaseEvents); }
+ QList<QKeyEvent *> pressEvents;
+ QList<QKeyEvent *> releaseEvents;
+ void keyPressEvent(QKeyEvent *e) override { pressEvents << e->clone(); }
+ void keyReleaseEvent(QKeyEvent *e) override { releaseEvents << e->clone(); }
};
void tst_QWebEngineView::unhandledKeyEventPropagation()
@@ -632,7 +732,7 @@ void tst_QWebEngineView::unhandledKeyEventPropagation()
QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool)));
webView.load(QUrl("qrc:///resources/keyboardEvents.html"));
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_VERIFY_WITH_TIMEOUT(loadFinishedSpy.size() > 0, 20000);
evaluateJavaScriptSync(webView.page(), "document.getElementById('first_div').focus()");
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("first_div"));
@@ -665,32 +765,42 @@ void tst_QWebEngineView::unhandledKeyEventPropagation()
// The page will consume the Tab key to change focus between elements while the arrow
// keys won't be used.
QCOMPARE(parentWidget.pressEvents.size(), 3);
- QCOMPARE(parentWidget.pressEvents[0].key(), (int)Qt::Key_Right);
- QCOMPARE(parentWidget.pressEvents[1].key(), (int)Qt::Key_Left);
- QCOMPARE(parentWidget.pressEvents[2].key(), (int)Qt::Key_Y);
+ QCOMPARE(parentWidget.pressEvents[0]->key(), (int)Qt::Key_Right);
+ QCOMPARE(parentWidget.pressEvents[1]->key(), (int)Qt::Key_Left);
+ QCOMPARE(parentWidget.pressEvents[2]->key(), (int)Qt::Key_Y);
// Key releases will all come back unconsumed.
- QCOMPARE(parentWidget.releaseEvents[0].key(), (int)Qt::Key_Right);
- QCOMPARE(parentWidget.releaseEvents[1].key(), (int)Qt::Key_Tab);
- QCOMPARE(parentWidget.releaseEvents[2].key(), (int)Qt::Key_Left);
- QCOMPARE(parentWidget.releaseEvents[3].key(), (int)Qt::Key_Y);
+ QCOMPARE(parentWidget.releaseEvents[0]->key(), (int)Qt::Key_Right);
+ QCOMPARE(parentWidget.releaseEvents[1]->key(), (int)Qt::Key_Tab);
+ QCOMPARE(parentWidget.releaseEvents[2]->key(), (int)Qt::Key_Left);
+ QCOMPARE(parentWidget.releaseEvents[3]->key(), (int)Qt::Key_Y);
}
void tst_QWebEngineView::horizontalScrollbarTest()
{
+#if QT_CONFIG(webengine_embedded_build)
+ // Embedded builds enable the OverlayScrollbar and Viewport features (see 'useEmbeddedSwitches' in web_engine_context.cpp).
+ // These features make the scrollbar simpler assuming we are on a device with small (usually touch) display.
+ // These scrollbars behave differently on mouse events.
+ QSKIP("Embedded builds have different scrollbar, skipping test.");
+#endif
QString html("<html><body>"
"<div style='width: 1000px; height: 1000px; background-color: green' />"
"</body></html>");
QWebEngineView view;
+ PageWithPaintListeners page;
+ view.setPage(&page);
view.setFixedSize(600, 600);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QSignalSpy firstPaintSpy(&page, &PageWithPaintListeners::firstContentfulPaint);
QSignalSpy loadSpy(view.page(), SIGNAL(loadFinished(bool)));
view.setHtml(html);
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QTRY_COMPARE(firstPaintSpy.size(), 1);
QVERIFY(view.page()->scrollPosition() == QPoint(0, 0));
QSignalSpy scrollSpy(view.page(), SIGNAL(scrollPositionChanged(QPointF)));
@@ -927,7 +1037,7 @@ public:
case QEvent::ContextMenu:
case QEvent::KeyPress:
case QEvent::KeyRelease:
-#ifndef QT_NO_WHEELEVENT
+#if QT_CONFIG(wheelevent)
case QEvent::Wheel:
#endif
++m_eventCounter;
@@ -961,7 +1071,7 @@ public:
private:
int m_eventCounter;
- QVector<QString> m_eventHistory;
+ QList<QString> m_eventHistory;
};
void tst_QWebEngineView::doNotSendMouseKeyboardEventsWhenDisabled()
@@ -982,7 +1092,7 @@ void tst_QWebEngineView::doNotSendMouseKeyboardEventsWhenDisabled()
QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
webView.setHtml("<html><head><title>Title</title></head><body>Hello"
"<input id=\"input\" type=\"text\"></body></html>");
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
// When the webView is enabled, the events are swallowed by it, and the parent widget
// does not receive any events, otherwise all events are processed by the parent widget.
@@ -1029,7 +1139,7 @@ void tst_QWebEngineView::stopSettingFocusWhenDisabled()
QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
webView.setHtml("<html><head><title>Title</title></head><body>Hello"
"<input id=\"input\" type=\"text\"></body></html>");
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QTRY_COMPARE_WITH_TIMEOUT(webView.hasFocus(), focusResult, 1000);
evaluateJavaScriptSync(webView.page(), "document.getElementById(\"input\").focus()");
@@ -1142,21 +1252,23 @@ void tst_QWebEngineView::focusInternalRenderWidgetHostViewQuickItem()
QWebEngineView *webView = new QWebEngineView;
QWebEngineSettings *settings = webView->page()->settings();
settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
- webView->resize(300, 300);
+ webView->resize(300, 100);
- QHBoxLayout *layout = new QHBoxLayout;
+ QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(label);
layout->addWidget(webView);
+ containerWidget->resize(300, 200);
containerWidget->setLayout(layout);
containerWidget->show();
QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data()));
// Load the content, and check that focus is not set.
QSignalSpy loadSpy(webView, SIGNAL(loadFinished(bool)));
- webView->setHtml("<html><head><title>Title</title></head><body>Hello"
- "<input id=\"input\" type=\"text\"></body></html>");
- QTRY_COMPARE(loadSpy.count(), 1);
+ webView->setHtml("<html><body>"
+ " <input id='input1' type='text'/>"
+ "</body></html>");
+ QTRY_COMPARE(loadSpy.size(), 1);
QTRY_COMPARE(webView->hasFocus(), false);
// Manually trigger focus.
@@ -1165,15 +1277,43 @@ void tst_QWebEngineView::focusInternalRenderWidgetHostViewQuickItem()
// Check that focus is set in QWebEngineView and all internal classes.
QTRY_COMPARE(webView->hasFocus(), true);
- QQuickWidget *renderWidgetHostViewQtDelegateWidget =
- qobject_cast<QQuickWidget *>(webView->focusProxy());
- QVERIFY(renderWidgetHostViewQtDelegateWidget);
- QTRY_COMPARE(renderWidgetHostViewQtDelegateWidget->hasFocus(), true);
+ QQuickWidget *webEngineQuickWidget = qobject_cast<QQuickWidget *>(webView->focusProxy());
+ QVERIFY(webEngineQuickWidget);
+ QTRY_COMPARE(webEngineQuickWidget->hasFocus(), true);
+
+ QQuickItem *root = webEngineQuickWidget->rootObject();
+ // The root item should not has focus, otherwise it would handle input events
+ // instead of the RenderWidgetHostViewQtDelegateItem.
+ QVERIFY(!root->hasFocus());
+
+ QCOMPARE(root->childItems().size(), 1);
+ QQuickItem *renderWidgetHostViewQtDelegateItem = root->childItems().at(0);
+ QVERIFY(renderWidgetHostViewQtDelegateItem);
+ QTRY_COMPARE(renderWidgetHostViewQtDelegateItem->hasFocus(), true);
+ // Test if QWebEngineView handles key events.
+ QTRY_COMPARE(renderWidgetHostViewQtDelegateItem->hasActiveFocus(), true);
+
+ // Key events should not be forwarded to the unfocused input field.
+ QTRY_COMPARE(evaluateJavaScriptSync(webView->page(),
+ "document.getElementById('input1').value").toString(),
+ QStringLiteral(""));
+ QTest::keyClick(webView->focusProxy(), Qt::Key_X);
+ QTest::qWait(100);
+ QTRY_COMPARE(evaluateJavaScriptSync(webView->page(),
+ "document.getElementById('input1').value").toString(),
+ QStringLiteral(""));
+
+ // Focus the input field. Focus rectangle is expected to appear around the input field.
+ evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').focus()");
+ QTRY_COMPARE(evaluateJavaScriptSync(webView->page(),
+ "document.activeElement.id").toString(),
+ QStringLiteral("input1"));
- QQuickItem *renderWidgetHostViewQuickItem =
- renderWidgetHostViewQtDelegateWidget->rootObject();
- QVERIFY(renderWidgetHostViewQuickItem);
- QTRY_COMPARE(renderWidgetHostViewQuickItem->hasFocus(), true);
+ // Test the focused input field with a key event.
+ QTest::keyClick(webView->focusProxy(), Qt::Key_X);
+ QTRY_COMPARE(evaluateJavaScriptSync(webView->page(),
+ "document.getElementById('input1').value").toString(),
+ QStringLiteral("x"));
}
void tst_QWebEngineView::doNotBreakLayout()
@@ -1203,6 +1343,9 @@ void tst_QWebEngineView::doNotBreakLayout()
void tst_QWebEngineView::changeLocale()
{
+ if (QTestPrivate::isRunningArmOnX86())
+ QSKIP("Does not work with QEMU. (QTBUG-94911)");
+
QStringList errorLines;
QUrl url("http://non.existent/");
@@ -1210,7 +1353,7 @@ void tst_QWebEngineView::changeLocale()
QWebEngineView viewDE;
QSignalSpy loadFinishedSpyDE(&viewDE, SIGNAL(loadFinished(bool)));
viewDE.load(url);
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.size(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty());
errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
@@ -1220,7 +1363,7 @@ void tst_QWebEngineView::changeLocale()
QWebEngineView viewEN;
QSignalSpy loadFinishedSpyEN(&viewEN, SIGNAL(loadFinished(bool)));
viewEN.load(url);
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyEN.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyEN.size(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewEN.page()).isEmpty());
errorLines = toPlainTextSync(viewEN.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
@@ -1233,13 +1376,56 @@ void tst_QWebEngineView::changeLocale()
// Check whether an existing QWebEngineView keeps the language settings after changing the default locale
viewDE.load(url);
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.size(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty());
errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("Die Website ist nicht erreichbar"));
}
+void tst_QWebEngineView::mixLangLocale_data()
+{
+ QTest::addColumn<QString>("locale");
+ QTest::addColumn<QByteArray>("formattedNumber");
+ QTest::newRow("en_DK") << "en-DK" << QByteArray("1.234.567.890");
+ QTest::newRow("de") << "de" << QByteArray("1.234.567.890");
+ QTest::newRow("de_CH") << "de-CH" << QByteArray("1’234’567’890");
+ QTest::newRow("eu_ES") << "eu-ES" << QByteArray("1.234.567.890");
+ QTest::newRow("hu_HU") << "hu-HU" << QByteArray("1\xC2\xA0""234\xC2\xA0""567\xC2\xA0""890"); // no-break spaces
+}
+
+void tst_QWebEngineView::mixLangLocale()
+{
+ QFETCH(QString, locale);
+ QFETCH(QByteArray, formattedNumber);
+
+ QLocale::setDefault(QLocale(locale));
+
+ QWebEngineView view;
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+
+ bool terminated = false;
+ auto sc = connect(view.page(), &QWebEnginePage::renderProcessTerminated, [&] () { terminated = true; });
+
+ view.load(QUrl("qrc:///resources/dummy.html"));
+ QTRY_VERIFY(terminated || loadSpy.size() == 1);
+
+ QVERIFY2(!terminated,
+ qPrintable(QString("Locale [%1] terminated: %2, loaded: %3").arg(locale).arg(terminated).arg(loadSpy.size())));
+ QVERIFY(loadSpy.first().first().toBool());
+
+ QString content = toPlainTextSync(view.page());
+ QVERIFY2(!content.isEmpty() && content.contains("test content"), qPrintable(content));
+
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "navigator.language").toString(), QLocale().bcp47Name());
+
+ if (locale == "eu-ES")
+ QEXPECT_FAIL("", "Basque number formatting is somehow dependent on environment", Continue);
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "Number(1234567890).toLocaleString()").toByteArray(), formattedNumber);
+
+ QLocale::setDefault(QLocale("en"));
+}
+
void tst_QWebEngineView::inputMethodsTextFormat_data()
{
QTest::addColumn<QString>("string");
@@ -1272,17 +1458,19 @@ void tst_QWebEngineView::inputMethodsTextFormat_data()
void tst_QWebEngineView::inputMethodsTextFormat()
{
- QWebEngineView view;
- view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
- QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ QWebEnginePage page;
+ QWebEngineView view(&page);
+ page.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+ QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
- view.setHtml("<html><body>"
+ page.setHtml("<html><body>"
" <input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/>"
"</body></html>");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
- evaluateJavaScriptSync(view.page(), "document.getElementById('input1').focus()");
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ evaluateJavaScriptSync(&page, "document.getElementById('input1').focus()");
QFETCH(QString, string);
QFETCH(int, start);
@@ -1306,8 +1494,8 @@ void tst_QWebEngineView::inputMethodsTextFormat()
attrs.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format));
QInputMethodEvent im(string, attrs);
- QVERIFY(QApplication::sendEvent(view.focusProxy(), &im));
- QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), string);
+ QApplication::sendEvent(view.focusProxy(), &im);
+ QTRY_COMPARE_WITH_TIMEOUT(evaluateJavaScriptSync(&page, "document.getElementById('input1').value").toString(), string, 20000);
}
void tst_QWebEngineView::keyboardEvents()
@@ -1316,7 +1504,7 @@ void tst_QWebEngineView::keyboardEvents()
view.show();
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
view.load(QUrl("qrc:///resources/keyboardEvents.html"));
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000);
QStringList elements;
elements << "first_div" << "second_div";
@@ -1435,17 +1623,21 @@ void tst_QWebEngineView::keyboardFocusAfterPopup()
QTRY_COMPARE(QApplication::focusWidget(), window.lineEdit);
// Trigger QCompleter's popup and select the first suggestion.
- QTest::keyClick(QApplication::focusWindow(), Qt::Key_T);
+ QTest::keyPress(QApplication::focusWindow(), Qt::Key_T);
+ QTest::keyRelease(QApplication::focusWindow(), Qt::Key_T);
QTRY_VERIFY(QApplication::activePopupWidget());
- QTest::keyClick(QApplication::focusWindow(), Qt::Key_Down);
- QTest::keyClick(QApplication::focusWindow(), Qt::Key_Enter);
+ QTest::keyPress(QApplication::focusWindow(), Qt::Key_Down);
+ QTest::keyRelease(QApplication::focusWindow(), Qt::Key_Down);
+ QTest::keyPress(QApplication::focusWindow(), Qt::Key_Enter);
+ QTest::keyRelease(QApplication::focusWindow(), Qt::Key_Enter);
// Due to FocusOnNavigationEnabled, focus should now move to the webView.
QTRY_COMPARE(QApplication::focusWidget(), window.webView->focusProxy());
// Keyboard events sent to the window should go to the <input> element.
- QVERIFY(loadFinishedSpy.count() || loadFinishedSpy.wait());
- QTest::keyClick(QApplication::focusWindow(), Qt::Key_X);
+ QVERIFY(loadFinishedSpy.size() || loadFinishedSpy.wait());
+ QTest::keyPress(QApplication::focusWindow(), Qt::Key_X);
+ QTest::keyRelease(QApplication::focusWindow(), Qt::Key_X);
QTRY_COMPARE(evaluateJavaScriptSync(window.webView->page(), "document.getElementById('input1').value").toString(),
QStringLiteral("x"));
}
@@ -1474,7 +1666,7 @@ void tst_QWebEngineView::mouseClick()
textInputCenter = elementCenter(view.page(), "input");
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
// Double click
@@ -1489,13 +1681,13 @@ void tst_QWebEngineView::mouseClick()
textInputCenter = elementCenter(view.page(), "input");
QTest::mouseMultiClick(view.focusProxy(), textInputCenter, 2);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(selectionChangedSpy.size(), 1);
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, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
// Triple click
@@ -1510,182 +1702,16 @@ void tst_QWebEngineView::mouseClick()
textInputCenter = elementCenter(view.page(), "input");
QTest::mouseMultiClick(view.focusProxy(), textInputCenter, 3);
QVERIFY(selectionChangedSpy.wait());
- QTRY_COMPARE(selectionChangedSpy.count(), 2);
+ QTRY_COMPARE(selectionChangedSpy.size(), 2);
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, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QCOMPARE(selectionChangedSpy.size(), 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;
@@ -1710,12 +1736,12 @@ void tst_QWebEngineView::postData()
// examine request
QStringList request = lines[0].split(" ", Qt::SkipEmptyParts);
- bool requestOk = request.length() > 2
+ bool requestOk = request.size() > 2
&& request[2].toUpper().startsWith("HTTP/")
&& request[0].toUpper() == "POST"
&& request[1] == "/";
if (!requestOk) // POST and HTTP/... can be switched(?)
- requestOk = request.length() > 2
+ requestOk = request.size() > 2
&& request[0].toUpper().startsWith("HTTP/")
&& request[2].toUpper() == "POST"
&& request[1] == "/";
@@ -1723,16 +1749,16 @@ void tst_QWebEngineView::postData()
// examine headers
int line = 1;
bool headersOk = true;
- for (; headersOk && line < lines.length(); line++) {
+ for (; headersOk && line < lines.size(); line++) {
QStringList headerParts = lines[line].split(":");
- if (headerParts.length() < 2)
+ if (headerParts.size() < 2)
break;
QString headerKey = headerParts[0].trimmed().toLower();
QString headerValue = headerParts[1].trimmed().toLower();
if (headerKey == "host")
headersOk = headersOk && (headerValue == "127.0.0.1")
- && (headerParts.length() == 3)
+ && (headerParts.size() == 3)
&& (headerParts[2].trimmed()
== QString::number(server.serverPort()));
if (headerKey == "content-type")
@@ -1741,12 +1767,12 @@ void tst_QWebEngineView::postData()
// examine body
bool bodyOk = true;
- if (lines.length() == line+2) {
+ if (lines.size() == line+2) {
QStringList postedFields = lines[line+1].split("&");
QMap<QString, QString> postedData;
- for (int i = 0; bodyOk && i < postedFields.length(); i++) {
+ for (int i = 0; bodyOk && i < postedFields.size(); i++) {
QStringList postedField = postedFields[i].split("=");
- if (postedField.length() == 2)
+ if (postedField.size() == 2)
postedData[QUrl::fromPercentEncoding(postedField[0].toLocal8Bit())]
= QUrl::fromPercentEncoding(postedField[1].toLocal8Bit());
else
@@ -1819,11 +1845,10 @@ void tst_QWebEngineView::postData()
void tst_QWebEngineView::inputFieldOverridesShortcuts()
{
+ QWebEngineView view;
bool actionTriggered = false;
- QAction *action = new QAction;
+ QAction *action = new QAction(&view);
connect(action, &QAction::triggered, [&actionTriggered] () { actionTriggered = true; });
-
- QWebEngineView view;
view.addAction(action);
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
@@ -1848,7 +1873,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts()
};
// The input form is not focused. The action is triggered on pressing Shift+Delete.
- action->setShortcut(Qt::SHIFT + Qt::Key_Delete);
+ action->setShortcut(Qt::SHIFT | Qt::Key_Delete);
QTest::keyClick(view.windowHandle(), Qt::Key_Delete, Qt::ShiftModifier);
QTRY_VERIFY(actionTriggered);
QCOMPARE(inputFieldValue(), QString("x"));
@@ -1884,7 +1909,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts()
// 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);
+ action->setShortcut(Qt::CTRL | Qt::Key_1);
QTest::keyClick(view.windowHandle(), Qt::Key_1, Qt::ControlModifier);
QTRY_VERIFY(actionTriggered);
QCOMPARE(inputFieldValue(), QString("yxx"));
@@ -1941,20 +1966,11 @@ public:
inputMethodPrivate->testContext = 0;
}
- virtual void showInputPanel()
- {
- m_visible = true;
- }
- virtual void hideInputPanel()
- {
- m_visible = false;
- }
- virtual bool isInputPanelVisible() const
- {
- return m_visible;
- }
+ void showInputPanel() override { m_visible = true; }
+ void hideInputPanel() override { m_visible = false; }
+ bool isInputPanelVisible() const override { return m_visible; }
- virtual void update(Qt::InputMethodQueries queries)
+ void update(Qt::InputMethodQueries queries) override
{
if (!qApp->focusObject())
return;
@@ -2050,13 +2066,14 @@ void tst_QWebEngineView::inputContextQueryInput()
view.setHtml("<html><body>"
" <input type='text' id='input1' value='' size='50'/>"
"</body></html>");
- QTRY_COMPARE(loadFinishedSpy.count(), 1);
- QCOMPARE(testContext.infos.count(), 0);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QCOMPARE(testContext.infos.size(), 0);
// Set focus on an input field.
QPoint textInputCenter = elementCenter(view.page(), "input1");
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
- QTRY_COMPARE(testContext.infos.count(), 2);
+ QTRY_COMPARE(testContext.infos.size(), 2);
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
foreach (const InputMethodInfo &info, testContext.infos) {
QCOMPARE(info.cursorPosition, 0);
@@ -2068,7 +2085,7 @@ void tst_QWebEngineView::inputContextQueryInput()
// Change content of an input field from JavaScript.
evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value='QtWebEngine';");
- QTRY_COMPARE(testContext.infos.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 11);
QCOMPARE(testContext.infos[0].anchorPosition, 11);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine"));
@@ -2077,7 +2094,7 @@ void tst_QWebEngineView::inputContextQueryInput()
// Change content of an input field by key press.
QTest::keyClick(view.focusProxy(), Qt::Key_Exclam);
- QTRY_COMPARE(testContext.infos.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 12);
QCOMPARE(testContext.infos[0].anchorPosition, 12);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!"));
@@ -2086,7 +2103,7 @@ void tst_QWebEngineView::inputContextQueryInput()
// Change cursor position.
QTest::keyClick(view.focusProxy(), Qt::Key_Left);
- QTRY_COMPARE(testContext.infos.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 11);
QCOMPARE(testContext.infos[0].anchorPosition, 11);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!"));
@@ -2101,8 +2118,8 @@ void tst_QWebEngineView::inputContextQueryInput()
QInputMethodEvent event("", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
}
- QTRY_COMPARE(testContext.infos.count(), 2);
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 2);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
// As a first step, Chromium moves the cursor to the start of the selection.
// We don't filter this in QtWebEngine because we don't know yet if this is part of a selection.
@@ -2127,8 +2144,8 @@ void tst_QWebEngineView::inputContextQueryInput()
QInputMethodEvent event("", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
}
- QTRY_COMPARE(testContext.infos.count(), 1);
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 0);
QCOMPARE(testContext.infos[0].anchorPosition, 0);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!"));
@@ -2142,9 +2159,9 @@ void tst_QWebEngineView::inputContextQueryInput()
QInputMethodEvent event("123", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
}
- QTRY_COMPARE(testContext.infos.count(), 1);
- QCOMPARE(testContext.infos[0].cursorPosition, 3);
- QCOMPARE(testContext.infos[0].anchorPosition, 3);
+ QTRY_COMPARE(testContext.infos.size(), 1);
+ QCOMPARE(testContext.infos[0].cursorPosition, 0);
+ QCOMPARE(testContext.infos[0].anchorPosition, 0);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!"));
QCOMPARE(testContext.infos[0].selectedText, QStringLiteral(""));
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!"));
@@ -2156,7 +2173,7 @@ void tst_QWebEngineView::inputContextQueryInput()
QInputMethodEvent event("", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
}
- QTRY_COMPARE(testContext.infos.count(), 2);
+ QTRY_COMPARE(testContext.infos.size(), 2);
foreach (const InputMethodInfo &info, testContext.infos) {
QCOMPARE(info.cursorPosition, 0);
QCOMPARE(info.anchorPosition, 0);
@@ -2173,7 +2190,7 @@ void tst_QWebEngineView::inputContextQueryInput()
event.setCommitString(QStringLiteral("123"), 0, 0);
QApplication::sendEvent(view.focusProxy(), &event);
}
- QTRY_COMPARE(testContext.infos.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 3);
QCOMPARE(testContext.infos[0].anchorPosition, 3);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("123QtWebEngine!"));
@@ -2183,7 +2200,7 @@ void tst_QWebEngineView::inputContextQueryInput()
// Focus out.
QTest::keyPress(view.focusProxy(), Qt::Key_Tab);
- QTRY_COMPARE(testContext.infos.count(), 1);
+ QTRY_COMPARE(testContext.infos.size(), 1);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral(""));
testContext.infos.clear();
}
@@ -2202,6 +2219,7 @@ void tst_QWebEngineView::inputMethods()
" <input type='text' id='input1' style='font-family: serif' value='' maxlength='20' size='50'/>"
"</body></html>");
QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QPoint textInputCenter = elementCenter(view.page(), "input1");
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
@@ -2226,7 +2244,7 @@ void tst_QWebEngineView::inputMethods()
QInputMethodEvent eventText(text, inputAttributes);
QApplication::sendEvent(view.focusProxy(), &eventText);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), text);
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
}
{
@@ -2235,7 +2253,7 @@ void tst_QWebEngineView::inputMethods()
eventText.setCommitString(text, 0, 0);
QApplication::sendEvent(view.focusProxy(), &eventText);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), text);
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
}
// ImMaximumTextLength
@@ -2299,6 +2317,7 @@ void tst_QWebEngineView::textSelectionInInputField()
" <input type='text' id='input1' value='QtWebEngine' size='50'/>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
// Tests for Selection when the Editor is NOT in Composition mode
@@ -2310,24 +2329,24 @@ void tst_QWebEngineView::textSelectionInInputField()
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11);
// There was no selection to be changed by the click
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent event(QString(), attributes);
event.setCommitString("XXX", 0, 0);
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineXXX"));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
event.setCommitString(QString(), -2, 2); // Erase two characters.
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineX"));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
event.setCommitString(QString(), -1, 1); // Erase one character.
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine"));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// Move to the start of the line
QTest::keyClick(view.focusProxy(), Qt::Key_Home);
@@ -2339,7 +2358,7 @@ void tst_QWebEngineView::textSelectionInInputField()
// Select to the end of the line
QTest::keyClick(view.focusProxy(), Qt::Key_End, Qt::ShiftModifier);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(selectionChangedSpy.size(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 2);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
@@ -2349,7 +2368,7 @@ void tst_QWebEngineView::textSelectionInInputField()
// Deselect the selection (this moves the current cursor to the end of the text)
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
@@ -2362,7 +2381,7 @@ void tst_QWebEngineView::textSelectionInInputField()
// Select to the start of the line
QTest::keyClick(view.focusProxy(), Qt::Key_Home, Qt::ShiftModifier);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QCOMPARE(selectionChangedSpy.size(), 3);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 9);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
@@ -2372,6 +2391,7 @@ void tst_QWebEngineView::textSelectionInInputField()
void tst_QWebEngineView::textSelectionOutOfInputField()
{
QWebEngineView view;
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
view.resize(640, 480);
view.show();
@@ -2381,35 +2401,33 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
" This is a text"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
QVERIFY(!view.hasSelection());
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, {}, view.geometry().center());
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
// Select text by ctrl+a
QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QVERIFY(view.hasSelection());
QCOMPARE(view.page()->selectedText(), QString("This is a text"));
// Deselect text by mouse click
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center());
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QTRY_COMPARE(selectionChangedSpy.size(), 2);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
// Select text by ctrl+a
QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QTRY_COMPARE(selectionChangedSpy.size(), 3);
QVERIFY(view.hasSelection());
QCOMPARE(view.page()->selectedText(), QString("This is a text"));
@@ -2417,8 +2435,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
view.hide();
view.page()->setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
view.show();
- QVERIFY(loadFinishedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 4);
+ QTRY_COMPARE(selectionChangedSpy.size(), 4);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
@@ -2429,8 +2446,9 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
" <input type='text' id='input1' value='QtWebEngine' size='50'/>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
@@ -2440,31 +2458,27 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
// Select the whole page by ctrl+a
QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QVERIFY(view.hasSelection());
QVERIFY(view.page()->selectedText().startsWith(QString("This is a text")));
// Remove selection by clicking into an input field
QPoint textInputCenter = elementCenter(view.page(), "input1");
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
- QVERIFY(selectionChangedSpy.wait());
+ QTRY_COMPARE(selectionChangedSpy.size(), 2);
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
- QCOMPARE(selectionChangedSpy.count(), 2);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
// Select the content of the input field by ctrl+a
QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QTRY_COMPARE(selectionChangedSpy.size(), 3);
QVERIFY(view.hasSelection());
QCOMPARE(view.page()->selectedText(), QString("QtWebEngine"));
// Deselect input field's text by mouse click
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center());
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 4);
+ QTRY_COMPARE(selectionChangedSpy.size(), 4);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
}
@@ -2508,9 +2522,10 @@ void tst_QWebEngineView::emptyInputMethodEvent()
" <input type='text' id='input1' value='QtWebEngine'/>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
// 1. Empty input method event does not clear text
QInputMethodEvent emptyEvent;
@@ -2556,9 +2571,10 @@ void tst_QWebEngineView::imeComposition()
" <input type='text' id='input1' value='QtWebEngine inputMethod'/>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
// Clear the selection, also cancel the ongoing composition if there is one.
{
@@ -2568,7 +2584,7 @@ void tst_QWebEngineView::imeComposition()
QInputMethodEvent event("", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
selectionChangedSpy.wait();
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
}
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod"));
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
@@ -2589,7 +2605,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// Send temporary text, which makes the editor has composition 'n'.
{
@@ -2601,7 +2617,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// Send commit text, which makes the editor conforms composition.
{
@@ -2614,7 +2630,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// 2. insert a character to the middle of the line.
@@ -2628,7 +2644,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// Send commit text, which makes the editor conforms composition.
{
@@ -2641,7 +2657,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 2);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 2);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// 3. Insert a character to the end of the line.
@@ -2659,7 +2675,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 25);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 25);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// Send commit text, which makes the editor conforms composition.
{
@@ -2672,7 +2688,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 26);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 26);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
// 4. Replace the selection.
@@ -2682,7 +2698,7 @@ void tst_QWebEngineView::imeComposition()
QTest::keyClick(view.focusProxy(), Qt::Key_Left, Qt::ShiftModifier | Qt::AltModifier);
#endif
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(selectionChangedSpy.size(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine inputMethodt"));
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 14);
@@ -2696,7 +2712,7 @@ void tst_QWebEngineView::imeComposition()
QApplication::sendEvent(view.focusProxy(), &event);
// The new composition should clear the previous selection
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
}
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine "));
// The cursor should be positioned at the end of the composition text
@@ -2716,7 +2732,7 @@ void tst_QWebEngineView::imeComposition()
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 15);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 15);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
selectionChangedSpy.clear();
@@ -2741,8 +2757,8 @@ void tst_QWebEngineView::imeComposition()
QApplication::sendEvent(view.focusProxy(), &event);
}
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString(""));
- QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
- QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("QtWebEngine"));
@@ -2758,7 +2774,7 @@ void tst_QWebEngineView::imeComposition()
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("QtWebEngine"));
- QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(selectionChangedSpy.size(), 0);
}
void tst_QWebEngineView::newlineInTextarea()
@@ -2773,6 +2789,7 @@ void tst_QWebEngineView::newlineInTextarea()
" <textarea rows='5' cols='1' id='input1'></textarea>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty());
@@ -2897,6 +2914,7 @@ void tst_QWebEngineView::imeJSInputEvents()
" <pre id='log'></pre>"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
evaluateJavaScriptSync(view.page(), "document.getElementById('input').focus()");
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
@@ -2911,7 +2929,7 @@ void tst_QWebEngineView::imeJSInputEvents()
}
// Simply committing text should not trigger any JS composition event.
- QTRY_COMPARE(logLines().count(), 3);
+ QTRY_COMPARE(logLines().size(), 3);
QCOMPARE(logLines()[0], QStringLiteral("[object InputEvent] beforeinput commit"));
QCOMPARE(logLines()[1], QStringLiteral("[object TextEvent] textInput commit"));
QCOMPARE(logLines()[2], QStringLiteral("[object InputEvent] input commit"));
@@ -2927,7 +2945,7 @@ void tst_QWebEngineView::imeJSInputEvents()
qApp->processEvents();
}
- QTRY_COMPARE(logLines().count(), 4);
+ QTRY_COMPARE(logLines().size(), 4);
QCOMPARE(logLines()[0], QStringLiteral("[object CompositionEvent] compositionstart "));
QCOMPARE(logLines()[1], QStringLiteral("[object InputEvent] beforeinput preedit"));
QCOMPARE(logLines()[2], QStringLiteral("[object CompositionEvent] compositionupdate preedit"));
@@ -2941,7 +2959,7 @@ void tst_QWebEngineView::imeJSInputEvents()
qApp->processEvents();
}
- QTRY_COMPARE(logLines().count(), 9);
+ QTRY_COMPARE(logLines().size(), 9);
QCOMPARE(logLines()[4], QStringLiteral("[object InputEvent] beforeinput commit"));
QCOMPARE(logLines()[5], QStringLiteral("[object CompositionEvent] compositionupdate commit"));
QCOMPARE(logLines()[6], QStringLiteral("[object TextEvent] textInput commit"));
@@ -2959,7 +2977,7 @@ void tst_QWebEngineView::imeJSInputEvents()
qApp->processEvents();
}
- QTRY_COMPARE(logLines().count(), 4);
+ QTRY_COMPARE(logLines().size(), 4);
QCOMPARE(logLines()[0], QStringLiteral("[object CompositionEvent] compositionstart "));
QCOMPARE(logLines()[1], QStringLiteral("[object InputEvent] beforeinput preedit"));
QCOMPARE(logLines()[2], QStringLiteral("[object CompositionEvent] compositionupdate preedit"));
@@ -2972,7 +2990,7 @@ void tst_QWebEngineView::imeJSInputEvents()
qApp->processEvents();
}
- QTRY_COMPARE(logLines().count(), 9);
+ QTRY_COMPARE(logLines().size(), 9);
QCOMPARE(logLines()[4], QStringLiteral("[object InputEvent] beforeinput "));
QCOMPARE(logLines()[5], QStringLiteral("[object CompositionEvent] compositionupdate "));
QCOMPARE(logLines()[6], QStringLiteral("[object TextEvent] textInput "));
@@ -3019,6 +3037,7 @@ void tst_QWebEngineView::imeCompositionQueryEvent()
" <input type='text' id='input1' />"
"</body></html>");
QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
evaluateJavaScriptSync(view.page(), "document.getElementById('input1').focus()");
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
@@ -3038,6 +3057,7 @@ void tst_QWebEngineView::imeCompositionQueryEvent()
}
QInputMethodQueryEvent srrndTextQuery(Qt::ImSurroundingText);
+ QInputMethodQueryEvent absolutePosQuery(Qt::ImAbsolutePosition);
QInputMethodQueryEvent cursorPosQuery(Qt::ImCursorPosition);
QInputMethodQueryEvent anchorPosQuery(Qt::ImAnchorPosition);
@@ -3049,16 +3069,18 @@ void tst_QWebEngineView::imeCompositionQueryEvent()
qApp->processEvents();
}
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("composition"));
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
+ QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
QApplication::sendEvent(input, &srrndTextQuery);
+ QApplication::sendEvent(input, &absolutePosQuery);
QApplication::sendEvent(input, &cursorPosQuery);
QApplication::sendEvent(input, &anchorPosQuery);
qApp->processEvents();
QTRY_COMPARE(srrndTextQuery.value(Qt::ImSurroundingText).toString(), QString(""));
- QTRY_COMPARE(cursorPosQuery.value(Qt::ImCursorPosition).toInt(), 11);
- QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 11);
+ QTRY_COMPARE(absolutePosQuery.value(Qt::ImAbsolutePosition).toInt(), 0);
+ QTRY_COMPARE(cursorPosQuery.value(Qt::ImCursorPosition).toInt(), 0);
+ QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 0);
// Send commit
{
@@ -3072,16 +3094,67 @@ void tst_QWebEngineView::imeCompositionQueryEvent()
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("composition"));
QApplication::sendEvent(input, &srrndTextQuery);
+ QApplication::sendEvent(input, &absolutePosQuery);
QApplication::sendEvent(input, &cursorPosQuery);
QApplication::sendEvent(input, &anchorPosQuery);
qApp->processEvents();
QTRY_COMPARE(srrndTextQuery.value(Qt::ImSurroundingText).toString(), QString("composition"));
+ QTRY_COMPARE(absolutePosQuery.value(Qt::ImAbsolutePosition).toInt(), 11);
QTRY_COMPARE(cursorPosQuery.value(Qt::ImCursorPosition).toInt(), 11);
QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 11);
+
+ // Test another composition to ensure that the cursor position is set correctly.
+ // In this case cursor will be at position 11 during input composition.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("123", attributes);
+ QApplication::sendEvent(input, &event);
+ qApp->processEvents();
+ }
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value")
+ .toString(),
+ QString("composition123"));
+ QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
+
+ QApplication::sendEvent(input, &srrndTextQuery);
+ QApplication::sendEvent(input, &absolutePosQuery);
+ QApplication::sendEvent(input, &cursorPosQuery);
+ QApplication::sendEvent(input, &anchorPosQuery);
+ qApp->processEvents();
+
+ QTRY_COMPARE(srrndTextQuery.value(Qt::ImSurroundingText).toString(), QString("composition"));
+ QTRY_COMPARE(absolutePosQuery.value(Qt::ImAbsolutePosition).toInt(), 11);
+ QTRY_COMPARE(cursorPosQuery.value(Qt::ImCursorPosition).toInt(), 11);
+ QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 11);
+
+ // Send commit
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("123");
+ QApplication::sendEvent(input, &event);
+ qApp->processEvents();
+ }
+
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value")
+ .toString(),
+ QString("composition123"));
+ QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 14);
+
+ QApplication::sendEvent(input, &srrndTextQuery);
+ QApplication::sendEvent(input, &absolutePosQuery);
+ QApplication::sendEvent(input, &cursorPosQuery);
+ QApplication::sendEvent(input, &anchorPosQuery);
+ qApp->processEvents();
+
+ QTRY_COMPARE(srrndTextQuery.value(Qt::ImSurroundingText).toString(), QString("composition123"));
+ QTRY_COMPARE(absolutePosQuery.value(Qt::ImAbsolutePosition).toInt(), 14);
+ QTRY_COMPARE(cursorPosQuery.value(Qt::ImCursorPosition).toInt(), 14);
+ QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 14);
}
-#ifndef QT_NO_CLIPBOARD
+#if QT_CONFIG(clipboard)
void tst_QWebEngineView::globalMouseSelection()
{
if (!QApplication::clipboard()->supportsSelection()) {
@@ -3103,20 +3176,20 @@ void tst_QWebEngineView::globalMouseSelection()
// Select text via JavaScript
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty());
// 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, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(selectionChangedSpy.size(), 2);
QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty());
// Select to the start of the line
QTest::keyClick(view.focusProxy(), Qt::Key_Home, Qt::ShiftModifier);
QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QCOMPARE(selectionChangedSpy.size(), 3);
QCOMPARE(QApplication::clipboard()->text(QClipboard::Selection), QStringLiteral("QtWebEngine"));
}
#endif
@@ -3142,7 +3215,7 @@ void tst_QWebEngineView::noContextMenu()
QTest::mouseMove(wrapper.windowHandle(), QPoint(10,10));
QTest::mouseClick(wrapper.windowHandle(), Qt::RightButton);
- QTRY_COMPARE(wrapper.findChildren<QMenu *>().count(), 1);
+ QTRY_COMPARE(wrapper.findChildren<QMenu *>().size(), 1);
QVERIFY(view.findChildren<QMenu *>().isEmpty());
}
@@ -3182,7 +3255,7 @@ void tst_QWebEngineView::contextMenu()
view.load(QUrl("about:blank"));
view.resize(640, 480);
view.show();
- QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.size(), 1);
QVERIFY(view.findChildren<QMenu *>().isEmpty());
QTest::mouseMove(view.windowHandle(), QPoint(10,10));
@@ -3190,9 +3263,9 @@ void tst_QWebEngineView::contextMenu()
// 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));
+ QVERIFY(!QTest::qWaitFor([&view] () { return view.findChildren<QMenu *>().size() > 0; }, 500));
} else {
- QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount);
+ QTRY_COMPARE(view.findChildren<QMenu *>().size(), childrenCount);
if (isCustomMenu) {
QCOMPARE(view.findChildren<QMenu *>().first(), customMenu);
}
@@ -3258,51 +3331,59 @@ void tst_QWebEngineView::webUIURLs_data()
QTest::addColumn<bool>("supported");
QTest::newRow("about") << QUrl("chrome://about") << false;
QTest::newRow("accessibility") << QUrl("chrome://accessibility") << true;
- QTest::newRow("appcache-internals") << QUrl("chrome://appcache-internals") << true;
+ QTest::newRow("app-service-internals") << QUrl("chrome://app-service-internals") << false;
+ QTest::newRow("app-settings") << QUrl("chrome://app-settings") << false;
QTest::newRow("apps") << QUrl("chrome://apps") << false;
+ QTest::newRow("attribution-internals") << QUrl("chrome://attribution-internals") << true;
+ QTest::newRow("autofill-internals") << QUrl("chrome://autofill-internals") << false;
QTest::newRow("blob-internals") << QUrl("chrome://blob-internals") << true;
QTest::newRow("bluetooth-internals") << QUrl("chrome://bluetooth-internals") << false;
QTest::newRow("bookmarks") << QUrl("chrome://bookmarks") << false;
- QTest::newRow("cache") << QUrl("chrome://cache") << false;
- QTest::newRow("chrome") << QUrl("chrome://chrome") << false;
QTest::newRow("chrome-urls") << QUrl("chrome://chrome-urls") << false;
QTest::newRow("components") << QUrl("chrome://components") << false;
+ QTest::newRow("connectors-internals") << QUrl("chrome://connectors-internals") << false;
QTest::newRow("crashes") << QUrl("chrome://crashes") << false;
QTest::newRow("credits") << QUrl("chrome://credits") << false;
- QTest::newRow("device-log") << QUrl("chrome://device-log") << false;
- QTest::newRow("devices") << QUrl("chrome://devices") << false;
+ QTest::newRow("device-log") << QUrl("chrome://device-log") << true;
QTest::newRow("dino") << QUrl("chrome://dino") << false; // It works but this is an error page
- QTest::newRow("dns") << QUrl("chrome://dns") << false;
+ QTest::newRow("discards") << QUrl("chrome://discards") << false;
+ QTest::newRow("download-internals") << QUrl("chrome://download-internals") << false;
QTest::newRow("downloads") << QUrl("chrome://downloads") << false;
QTest::newRow("extensions") << QUrl("chrome://extensions") << false;
+ QTest::newRow("extensions-internals") << QUrl("chrome://extensions-internals") << false;
QTest::newRow("flags") << QUrl("chrome://flags") << false;
- QTest::newRow("flash") << QUrl("chrome://flash") << false;
QTest::newRow("gcm-internals") << QUrl("chrome://gcm-internals") << false;
QTest::newRow("gpu") << QUrl("chrome://gpu") << true;
QTest::newRow("help") << QUrl("chrome://help") << false;
QTest::newRow("histograms") << QUrl("chrome://histograms") << true;
+ QTest::newRow("history") << QUrl("chrome://history") << false;
+ QTest::newRow("history-clusters-internals") << QUrl("chrome://history-clusters-internals") << false;
QTest::newRow("indexeddb-internals") << QUrl("chrome://indexeddb-internals") << true;
QTest::newRow("inspect") << QUrl("chrome://inspect") << false;
+ QTest::newRow("interstitials") << QUrl("chrome://interstitials") << false;
QTest::newRow("invalidations") << QUrl("chrome://invalidations") << false;
QTest::newRow("linux-proxy-config") << QUrl("chrome://linux-proxy-config") << false;
QTest::newRow("local-state") << QUrl("chrome://local-state") << false;
+ QTest::newRow("management") << QUrl("chrome://management") << false;
+ QTest::newRow("media-engagement") << QUrl("chrome://media-engagement") << false;
QTest::newRow("media-internals") << QUrl("chrome://media-internals") << true;
+ QTest::newRow("nacl") << QUrl("chrome://nacl") << false;
QTest::newRow("net-export") << QUrl("chrome://net-export") << false;
- QTest::newRow("net-internals") << QUrl("chrome://net-internals") << false;
+ QTest::newRow("net-internals") << QUrl("chrome://net-internals") << true;
QTest::newRow("network-error") << QUrl("chrome://network-error") << false;
QTest::newRow("network-errors") << QUrl("chrome://network-errors") << true;
- QTest::newRow("newtab") << QUrl("chrome://newtab") << false;
QTest::newRow("ntp-tiles-internals") << QUrl("chrome://ntp-tiles-internals") << false;
QTest::newRow("omnibox") << QUrl("chrome://omnibox") << false;
+ QTest::newRow("optimization-guide-internals") << QUrl("chrome://optimization-guide-internals") << false;
QTest::newRow("password-manager-internals") << QUrl("chrome://password-manager-internals") << false;
QTest::newRow("policy") << QUrl("chrome://policy") << false;
QTest::newRow("predictors") << QUrl("chrome://predictors") << false;
+ QTest::newRow("prefs-internals") << QUrl("chrome://prefs-internals") << false;
QTest::newRow("print") << QUrl("chrome://print") << false;
QTest::newRow("process-internals") << QUrl("chrome://process-internals") << true;
- QTest::newRow("profiler") << QUrl("chrome://profiler") << false;
QTest::newRow("quota-internals") << QUrl("chrome://quota-internals") << true;
QTest::newRow("safe-browsing") << QUrl("chrome://safe-browsing") << false;
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
QTest::newRow("sandbox") << QUrl("chrome://sandbox") << true;
#else
QTest::newRow("sandbox") << QUrl("chrome://sandbox") << false;
@@ -3311,19 +3392,23 @@ void tst_QWebEngineView::webUIURLs_data()
QTest::newRow("settings") << QUrl("chrome://settings") << false;
QTest::newRow("signin-internals") << QUrl("chrome://signin-internals") << false;
QTest::newRow("site-engagement") << QUrl("chrome://site-engagement") << false;
- QTest::newRow("suggestions") << QUrl("chrome://suggestions") << false;
- QTest::newRow("supervised-user-internals") << QUrl("chrome://supervised-user-internals") << false;
QTest::newRow("sync-internals") << QUrl("chrome://sync-internals") << false;
QTest::newRow("system") << QUrl("chrome://system") << false;
QTest::newRow("terms") << QUrl("chrome://terms") << false;
- QTest::newRow("thumbnails") << QUrl("chrome://thumbnails") << false;
- QTest::newRow("tracing") << QUrl("chrome://tracing") << false;
+ QTest::newRow("tracing") << QUrl("chrome://tracing") << true;
QTest::newRow("translate-internals") << QUrl("chrome://translate-internals") << false;
+ QTest::newRow("ukm") << QUrl("chrome://ukm") << true;
QTest::newRow("usb-internals") << QUrl("chrome://usb-internals") << false;
- QTest::newRow("user-actions") << QUrl("chrome://user-actions") << false;
+ QTest::newRow("user-actions") << QUrl("chrome://user-actions") << true;
QTest::newRow("version") << QUrl("chrome://version") << false;
+ QTest::newRow("web-app-internals") << QUrl("chrome://web-app-internals") << false;
+#if QT_CONFIG(webengine_webrtc)
QTest::newRow("webrtc-internals") << QUrl("chrome://webrtc-internals") << true;
- QTest::newRow("webrtc-logs") << QUrl("chrome://webrtc-logs") << false;
+#if QT_CONFIG(webengine_extensions)
+ QTest::newRow("webrtc-logs") << QUrl("chrome://webrtc-logs") << true;
+#endif // QT_CONFIG(webengine_extensions)
+#endif // QT_CONFIG(webengine_webrtc)
+ QTest::newRow("whats-new") << QUrl("chrome://whats-new") << false;
}
void tst_QWebEngineView::webUIURLs()
@@ -3335,7 +3420,7 @@ void tst_QWebEngineView::webUIURLs()
view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
view.load(url);
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 90000);
QCOMPARE(loadFinishedSpy.takeFirst().at(0).toBool(), supported);
}
@@ -3344,7 +3429,7 @@ void tst_QWebEngineView::visibilityState()
QWebEngineView view;
QSignalSpy spy(&view, &QWebEngineView::loadFinished);
view.load(QStringLiteral("about:blank"));
- QVERIFY(spy.count() || spy.wait());
+ QVERIFY(spy.size() || spy.wait());
QVERIFY(spy.takeFirst().takeFirst().toBool());
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.visibilityState").toString(), QStringLiteral("hidden"));
view.show();
@@ -3359,7 +3444,7 @@ void tst_QWebEngineView::visibilityState2()
view.show();
view.load(QStringLiteral("about:blank"));
view.hide();
- QVERIFY(spy.count() || spy.wait());
+ QVERIFY(spy.size() || spy.wait());
QVERIFY(spy.takeFirst().takeFirst().toBool());
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.visibilityState").toString(), QStringLiteral("hidden"));
}
@@ -3372,8 +3457,8 @@ void tst_QWebEngineView::visibilityState3()
QSignalSpy spy2(&page2, &QWebEnginePage::loadFinished);
page1.load(QStringLiteral("about:blank"));
page2.load(QStringLiteral("about:blank"));
- QVERIFY(spy1.count() || spy1.wait());
- QVERIFY(spy2.count() || spy2.wait());
+ QVERIFY(spy1.size() || spy1.wait());
+ QVERIFY(spy2.size() || spy2.wait());
QWebEngineView view;
view.setPage(&page1);
view.show();
@@ -3437,7 +3522,27 @@ void tst_QWebEngineView::deletePage()
QVERIFY(view.page());
QSignalSpy spy(view.page(), &QWebEnginePage::loadFinished);
view.page()->load(QStringLiteral("about:blank"));
- QTRY_VERIFY(spy.count());
+ QTRY_VERIFY(spy.size());
+}
+
+void tst_QWebEngineView::autoDeleteOnExternalPageDelete()
+{
+ QPointer<QWebEngineView> view = new QWebEngineView;
+ QPointer<QWebEnginePage> page = new QWebEnginePage;
+ auto sg = qScopeGuard([&] () { delete view; delete page; });
+
+ QSignalSpy spy(page, &QWebEnginePage::loadFinished);
+ view->setPage(page);
+ view->show();
+ view->resize(320, 240);
+ page->load(QUrl("about:blank"));
+ QTRY_VERIFY(spy.size());
+ QVERIFY(page->parent() != view);
+
+ auto sc = QObject::connect(page, &QWebEnginePage::destroyed, view, &QWebEngineView::deleteLater);
+ QTimer::singleShot(0, page, &QObject::deleteLater);
+ QTRY_VERIFY(!page);
+ QTRY_VERIFY(!view);
}
class TestView : public QWebEngineView {
@@ -3464,7 +3569,7 @@ void tst_QWebEngineView::closeOpenerTab()
testView->settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
QSignalSpy loadFinishedSpy(testView, SIGNAL(loadFinished(bool)));
testView->setUrl(QStringLiteral("about:blank"));
- QTRY_VERIFY(loadFinishedSpy.count());
+ QTRY_VERIFY(loadFinishedSpy.size());
testView->page()->runJavaScript(QStringLiteral("window.open('about:blank','_blank')"));
QTRY_COMPARE(testView->createdWindows.size(), 1);
auto *newView = testView->createdWindows.at(0);
@@ -3483,9 +3588,13 @@ void tst_QWebEngineView::switchPage()
QWebEnginePage page2(&profile);
QSignalSpy loadFinishedSpy1(&page1, SIGNAL(loadFinished(bool)));
QSignalSpy loadFinishedSpy2(&page2, SIGNAL(loadFinished(bool)));
+ // TODO fixme: page without the view has no real widget behind, so
+ // reading graphical content will fail, add view for now.
+ QWebEngineView webView1(&page1, nullptr);
+ QWebEngineView webView2(&page2, nullptr);
page1.setHtml("<html><body bgcolor=\"#000000\"></body></html>");
page2.setHtml("<html><body bgcolor=\"#ffffff\"></body></html>");
- QTRY_VERIFY(loadFinishedSpy1.count() && loadFinishedSpy2.count());
+ QTRY_VERIFY(loadFinishedSpy1.size() && loadFinishedSpy2.size());
QWebEngineView webView;
webView.resize(300,300);
webView.show();
@@ -3526,7 +3635,7 @@ void tst_QWebEngineView::setViewDeletesImplicitPage()
QWebEngineView view;
QPointer<QWebEnginePage> implicitPage = view.page();
QWebEnginePage explicitPage;
- explicitPage.setView(&view);
+ view.setPage(&explicitPage);
QCOMPARE(view.page(), &explicitPage);
QVERIFY(!implicitPage); // should be deleted
}
@@ -3547,8 +3656,8 @@ void tst_QWebEngineView::setViewPreservesExplicitPage()
QWebEngineView view;
QPointer<QWebEnginePage> explicitPage1 = new QWebEnginePage(&view);
QPointer<QWebEnginePage> explicitPage2 = new QWebEnginePage(&view);
- explicitPage1->setView(&view);
- explicitPage2->setView(&view);
+ view.setPage(explicitPage1.data());
+ view.setPage(explicitPage2.data());
QCOMPARE(view.page(), explicitPage2.data());
QVERIFY(explicitPage1); // should not be deleted
}
@@ -3556,17 +3665,342 @@ void tst_QWebEngineView::setViewPreservesExplicitPage()
void tst_QWebEngineView::closeDiscardsPage()
{
QWebEngineProfile profile;
- QWebEnginePage page(&profile);
- QWebEngineView view;
- view.setPage(&page);
+ QWebEngineView view(&profile, nullptr);
view.resize(300, 300);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
- QCOMPARE(page.isVisible(), true);
- QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(view.page()->isVisible(), true);
+ QCOMPARE(view.page()->lifecycleState(), QWebEnginePage::LifecycleState::Active);
view.close();
- QCOMPARE(page.isVisible(), false);
- QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(view.page()->isVisible(), false);
+ QCOMPARE(view.page()->lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+}
+
+
+void tst_QWebEngineView::loadAfterRendererCrashed()
+{
+ QWebEngineView view;
+ view.resize(640, 480);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ bool terminated = false;
+ connect(view.page(), &QWebEnginePage::renderProcessTerminated, [&] () { terminated = true; });
+ view.load(QUrl("chrome://crash"));
+ QTRY_VERIFY_WITH_TIMEOUT(terminated, 30000);
+
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("qrc:///resources/dummy.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QVERIFY(loadSpy.first().first().toBool());
+}
+
+void tst_QWebEngineView::inspectElement()
+{
+ QWebEngineView view;
+ view.resize(640, 480);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ auto page = view.page();
+ // shouldn't do anything until page is set
+ page->triggerAction(QWebEnginePage::InspectElement);
+ QTest::qWait(100);
+
+ QSignalSpy spy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("data:text/plain,foobarbaz"));
+ QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 12000);
+
+ // shouldn't do anything since inspector is not attached
+ page->triggerAction(QWebEnginePage::InspectElement);
+ QTest::qWait(100);
+
+ QWebEngineView inspectorView;
+ inspectorView.resize(640, 480);
+ inspectorView.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&inspectorView));
+ inspectorView.page()->setInspectedPage(page);
+
+ page->triggerAction(QWebEnginePage::InspectElement);
+ // TODO verify somehow
+ QTest::qWait(100);
+}
+
+void tst_QWebEngineView::navigateOnDrop_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<bool>("navigateOnDrop");
+ QTest::newRow("file") << QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).absoluteFilePath("resources/dummy.html")) << true;
+ QTest::newRow("qrc") << QUrl("qrc:///resources/dummy.html") << true;
+ QTest::newRow("file_no_navigate") << QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).absoluteFilePath("resources/dummy.html")) << false;
+ QTest::newRow("qrc_no_navigate") << QUrl("qrc:///resources/dummy.html") << false;
+}
+
+void tst_QWebEngineView::navigateOnDrop()
+{
+ QFETCH(QUrl, url);
+ QFETCH(bool, navigateOnDrop);
+ struct WebEngineView : QWebEngineView {
+ QWebEngineView* createWindow(QWebEnginePage::WebWindowType /* type */) override { return this; }
+ } view;
+ view.page()->settings()->setAttribute(QWebEngineSettings::NavigateOnDropEnabled, navigateOnDrop);
+ view.resize(640, 480);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ QMimeData mimeData;
+ mimeData.setUrls({ url });
+
+ auto sendEvents = [&] () {
+ QDragEnterEvent dee(view.rect().center(), Qt::CopyAction, &mimeData, Qt::LeftButton, Qt::NoModifier);
+ QApplication::sendEvent(&view, &dee);
+ QDropEvent de(view.rect().center(), Qt::CopyAction, &mimeData, Qt::LeftButton, Qt::NoModifier);
+ QApplication::sendEvent(&view, &de);
+ };
+
+ sendEvents();
+ if (navigateOnDrop) {
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QVERIFY(loadSpy.last().first().toBool());
+ QCOMPARE(view.url(), url);
+ } else {
+ QTest::qWait(500);
+ QCOMPARE(loadSpy.size(), 0);
+ QVERIFY(view.url() != url);
+ }
+
+ // Check dynamically changing the setting
+ loadSpy.clear();
+ view.page()->settings()->setAttribute(QWebEngineSettings::NavigateOnDropEnabled, !navigateOnDrop);
+ view.setUrl(QUrl("about:blank"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+
+ sendEvents();
+ if (!navigateOnDrop) {
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(loadSpy.last().first().toBool());
+ QCOMPARE(view.url(), url);
+ } else {
+ QTest::qWait(500);
+ QCOMPARE(loadSpy.size(), 1);
+ QVERIFY(view.url() != url);
+ }
+}
+
+void tst_QWebEngineView::emptyUriListOnDrop()
+{
+ QWebEngineView view;
+ view.resize(640, 480);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QMimeData mimeData;
+ mimeData.setUrls({}); // creates an empty uri-list MIME type entry
+ QVERIFY(mimeData.hasUrls());
+
+ QDragEnterEvent dee(view.rect().center(), Qt::CopyAction, &mimeData, Qt::LeftButton,
+ Qt::NoModifier);
+ QApplication::sendEvent(&view, &dee);
+ QDropEvent de(view.rect().center(), Qt::CopyAction, &mimeData, Qt::LeftButton, Qt::NoModifier);
+ QApplication::sendEvent(&view, &de);
+
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ view.setUrl(QUrl("about:blank"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+}
+
+void tst_QWebEngineView::datalist()
+{
+ QString html("<html><body>"
+ "<input id='browserInput' list='browserDatalist'>"
+ "<datalist id='browserDatalist'>"
+ " <option value='Internet Explorer'>"
+ " <option value='Firefox'>"
+ " <option value='Chrome'>"
+ " <option value='Opera'>"
+ " <option value='Safari'>"
+ "</datalist>"
+ "</body></html>");
+
+ QWebEngineView view;
+ view.resize(200, 400);
+ view.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ view.setHtml(html);
+ QTRY_COMPARE(loadSpy.size(), 1);
+
+ QString listValuesJS("(function() {"
+ " var browserDatalist = document.getElementById('browserDatalist');"
+ " var options = browserDatalist.options;"
+ " var result = [];"
+ " for (let i = 0; i < options.length; ++i) {"
+ " result.push(options[i].value);"
+ " }"
+ " return result;"
+ "})();");
+ QStringList values = evaluateJavaScriptSync(view.page(), listValuesJS).toStringList();
+ QCOMPARE(values, QStringList({ "Internet Explorer", "Firefox", "Chrome", "Opera", "Safari" }));
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('browserInput').value;")
+ .toString(),
+ QStringLiteral(""));
+
+ auto listView = [&view]() -> QListView * {
+ if (QApplication::topLevelWidgets().size() == 1) {
+ // No popup case.
+ return nullptr;
+ }
+
+ QWidget *autofillPopupWidget = nullptr;
+ for (QWidget *w : QApplication::topLevelWidgets()) {
+ if (w != &view) {
+ autofillPopupWidget = w;
+ break;
+ }
+ }
+
+ if (!autofillPopupWidget)
+ return nullptr;
+
+ for (QObject *o : autofillPopupWidget->children()) {
+ if (QListView *listView = qobject_cast<QListView *>(o))
+ return listView;
+ }
+
+ return nullptr;
+ };
+
+ // Make sure there is no open popup yet.
+ QVERIFY(!listView());
+ // Click in the input field.
+ QPoint browserInputCenter = elementCenter(view.page(), "browserInput");
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, browserInputCenter);
+ // Wait for the popup.
+ QTRY_VERIFY(listView());
+
+ // No suggestion is selected.
+ QCOMPARE(listView()->currentIndex(), QModelIndex());
+ QCOMPARE(listView()->model()->rowCount(), 5);
+
+ // Accepting suggestion does nothing.
+ QTest::keyClick(view.windowHandle(), Qt::Key_Enter);
+ QVERIFY(listView());
+ QCOMPARE(listView()->currentIndex(), QModelIndex());
+
+ // Escape should close popup.
+ QTest::keyClick(view.windowHandle(), Qt::Key_Escape);
+ QTRY_VERIFY(!listView());
+
+ // Key Down should open the popup and select the first suggestion.
+ QTest::keyClick(view.windowHandle(), Qt::Key_Down);
+ QTRY_VERIFY(listView());
+ QCOMPARE(listView()->currentIndex().row(), 0);
+
+ // Test keyboard navigation in list.
+ QTest::keyClick(view.windowHandle(), Qt::Key_Up);
+ QCOMPARE(listView()->currentIndex().row(), 4);
+ QTest::keyClick(view.windowHandle(), Qt::Key_Up);
+ QCOMPARE(listView()->currentIndex().row(), 3);
+ QTest::keyClick(view.windowHandle(), Qt::Key_PageDown);
+ QCOMPARE(listView()->currentIndex().row(), 4);
+ QTest::keyClick(view.windowHandle(), Qt::Key_PageUp);
+ QCOMPARE(listView()->currentIndex().row(), 0);
+ QTest::keyClick(view.windowHandle(), Qt::Key_Down);
+ QCOMPARE(listView()->currentIndex().row(), 1);
+ QTest::keyClick(view.windowHandle(), Qt::Key_Down);
+ QCOMPARE(listView()->currentIndex().row(), 2);
+
+ // Test accepting suggestion.
+ QCOMPARE(static_cast<QStringListModel *>(listView()->model())
+ ->data(listView()->currentIndex())
+ .toString(),
+ QStringLiteral("Chrome"));
+ QTest::keyClick(view.windowHandle(), Qt::Key_Enter);
+ QTRY_COMPARE(
+ evaluateJavaScriptSync(view.page(), "document.getElementById('browserInput').value")
+ .toString(),
+ QStringLiteral("Chrome"));
+ // Accept closes popup.
+ QTRY_VERIFY(!listView());
+
+ // Clear input field, should not trigger popup.
+ evaluateJavaScriptSync(view.page(), "document.getElementById('browserInput').value = ''");
+ QVERIFY(!listView());
+
+ // Filter suggestions.
+ QTest::keyClick(view.windowHandle(), Qt::Key_F);
+ QTRY_VERIFY(listView());
+ QCOMPARE(listView()->model()->rowCount(), 2);
+ QCOMPARE(listView()->currentIndex(), QModelIndex());
+ QCOMPARE(static_cast<QStringListModel *>(listView()->model())
+ ->data(listView()->model()->index(0, 0))
+ .toString(),
+ QStringLiteral("Firefox"));
+ QCOMPARE(static_cast<QStringListModel *>(listView()->model())
+ ->data(listView()->model()->index(1, 0))
+ .toString(),
+ QStringLiteral("Safari"));
+ QTest::keyClick(view.windowHandle(), Qt::Key_I);
+ QTRY_COMPARE(listView()->model()->rowCount(), 1);
+ QCOMPARE(listView()->currentIndex(), QModelIndex());
+ QCOMPARE(static_cast<QStringListModel *>(listView()->model())
+ ->data(listView()->model()->index(0, 0))
+ .toString(),
+ QStringLiteral("Firefox"));
+ QTest::keyClick(view.windowHandle(), Qt::Key_L);
+ // Mismatch should close popup.
+ QTRY_VERIFY(!listView());
+ QTRY_COMPARE(
+ evaluateJavaScriptSync(view.page(), "document.getElementById('browserInput').value")
+ .toString(),
+ QStringLiteral("fil"));
+}
+
+class ConsolePage : public QWebEnginePage
+{
+ Q_OBJECT
+public:
+ ConsolePage(QObject *parent = nullptr) : QWebEnginePage(parent) { }
+ void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message,
+ int lineNumber, const QString &sourceID) override
+ {
+ Q_UNUSED(level)
+ Q_UNUSED(lineNumber)
+ Q_UNUSED(sourceID)
+ if (message.contains("TEST_KEY:Shift"))
+ emit done();
+ }
+signals:
+ void done();
+};
+
+//qtbug_113704
+void tst_QWebEngineView::longKeyEventText()
+{
+ const QString html(QStringLiteral("<html><body><p>TEST</p>"
+ "<script>"
+ "document.addEventListener('keydown', (event)=> {"
+ "console.log('TEST_KEY:' + event.key);"
+ "});"
+ "</script>"
+ "</body></html>"));
+
+ QWebEngineView view;
+ ConsolePage page;
+ view.setPage(&page);
+ QSignalSpy loadFinishedSpy(view.page(), &QWebEnginePage::loadFinished);
+ view.resize(200, 400);
+ view.show();
+ view.setHtml(html);
+ QTRY_VERIFY(loadFinishedSpy.size());
+ QSignalSpy consoleMessageSpy(&page, &ConsolePage::done);
+ Qt::Key key(Qt::Key_Shift);
+ QKeyEvent event(QKeyEvent::KeyPress, key, Qt::NoModifier, QKeySequence(key).toString());
+ QApplication::sendEvent(view.focusProxy(), &event);
+ QTRY_VERIFY(consoleMessageSpy.size());
}
QTEST_MAIN(tst_QWebEngineView)
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
deleted file mode 100644
index a09be0399..000000000
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
+++ /dev/null
@@ -1,10 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>resources/index.html</file>
- <file>resources/frame_a.html</file>
- <file>resources/input_types.html</file>
- <file>resources/scrolltest_page.html</file>
- <file>resources/keyboardEvents.html</file>
- <file>resources/image2.png</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/widgets/schemes/CMakeLists.txt b/tests/auto/widgets/schemes/CMakeLists.txt
new file mode 100644
index 000000000..5299b3148
--- /dev/null
+++ b/tests/auto/widgets/schemes/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_schemes
+ SOURCES
+ tst_schemes.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
diff --git a/tests/auto/widgets/schemes/schemes.pro b/tests/auto/widgets/schemes/schemes.pro
deleted file mode 100644
index e56bbe8f7..000000000
--- a/tests/auto/widgets/schemes/schemes.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-include(../tests.pri)
-exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
-QT *= core-private gui-private
diff --git a/tests/auto/widgets/schemes/tst_schemes.cpp b/tests/auto/widgets/schemes/tst_schemes.cpp
index a4a0e34ff..188c112e4 100644
--- a/tests/auto/widgets/schemes/tst_schemes.cpp
+++ b/tests/auto/widgets/schemes/tst_schemes.cpp
@@ -1,47 +1,50 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QtTest>
-#include <qwebengineview.h>
#include <qwebenginepage.h>
#include <qwebengineprofile.h>
#include <qwebenginesettings.h>
+#include <qwebengineurlrequestjob.h>
+#include <qwebengineurlscheme.h>
+#include <qwebengineurlschemehandler.h>
+#include <qwebengineview.h>
+#include <widgetutil.h>
class tst_Schemes : public QObject
{
Q_OBJECT
private Q_SLOTS:
+ void initTestCase();
void unknownUrlSchemePolicy_data();
void unknownUrlSchemePolicy();
+ void customSchemeFragmentNavigation_data();
+ void customSchemeFragmentNavigation();
};
+void tst_Schemes::initTestCase()
+{
+ QWebEngineUrlScheme pathScheme("path");
+ pathScheme.setSyntax(QWebEngineUrlScheme::Syntax::Path);
+ QWebEngineUrlScheme::registerScheme(pathScheme);
+
+ QWebEngineUrlScheme hostScheme("host");
+ hostScheme.setSyntax(QWebEngineUrlScheme::Syntax::Host);
+ QWebEngineUrlScheme::registerScheme(hostScheme);
+
+ QWebEngineUrlScheme hostAndPortScheme("hostandport");
+ hostAndPortScheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort);
+ hostAndPortScheme.setDefaultPort(3000);
+ QWebEngineUrlScheme::registerScheme(hostAndPortScheme);
+
+ QWebEngineUrlScheme hostPortUserInfoScheme("hostportuserinfo");
+ hostPortUserInfoScheme.setSyntax(QWebEngineUrlScheme::Syntax::HostPortAndUserInformation);
+ hostPortUserInfoScheme.setDefaultPort(3000);
+ QWebEngineUrlScheme::registerScheme(hostPortUserInfoScheme);
+}
+
class AcceptNavigationRequestHandler : public QWebEnginePage
{
public:
@@ -118,5 +121,161 @@ void tst_Schemes::unknownUrlSchemePolicy()
QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0);
}
+class CustomScheme : public QWebEngineUrlSchemeHandler
+{
+public:
+ CustomScheme(const QString &linkUrl) : m_linkUrl(linkUrl) { }
+
+ void requestStarted(QWebEngineUrlRequestJob *requestJob) override
+ {
+ QString html = QString("<html><body>"
+ "<p style='height: 2000px;'>"
+ "<a href='%1' id='link'>Click link</a>"
+ "</p><p id='anchor'>Anchor</p>"
+ "</body></html>")
+ .arg(m_linkUrl);
+ QBuffer *buffer = new QBuffer(requestJob);
+ buffer->setData(html.toUtf8());
+ requestJob->reply("text/html", buffer);
+ }
+
+ QString m_linkUrl;
+};
+
+void tst_Schemes::customSchemeFragmentNavigation_data()
+{
+ QTest::addColumn<QUrl>("baseUrl");
+ QTest::addColumn<QString>("linkUrl");
+ QTest::addColumn<QUrl>("expectedUrl");
+
+ // Path syntax
+ // - Preserves each part of the URL after navigation
+ QTest::newRow("Path syntax, path only, relative url")
+ << QUrl("path://path") << "#anchor" << QUrl("path://path#anchor");
+ QTest::newRow("Path syntax, path only, absolute url")
+ << QUrl("path://path") << "path://path#anchor" << QUrl("path://path#anchor");
+ QTest::newRow("Path syntax, host/path, relative url")
+ << QUrl("path://host/path") << "#anchor" << QUrl("path://host/path#anchor");
+ QTest::newRow("Path syntax, host/path, absolute url")
+ << QUrl("path://host/path") << "path://host/path#anchor"
+ << QUrl("path://host/path#anchor");
+ QTest::newRow("Path syntax, host:port, relative url")
+ << QUrl("path://host:3000") << "#anchor" << QUrl("path://host:3000#anchor");
+ QTest::newRow("Path syntax, host:port, absolute url")
+ << QUrl("path://host:3000") << "path://host:3000#anchor"
+ << QUrl("path://host:3000#anchor");
+ QTest::newRow("Path syntax, userinfo@host:port, relative url")
+ << QUrl("path://user:password@host:3000") << "#anchor"
+ << QUrl("path://user:password@host:3000#anchor");
+ QTest::newRow("Path syntax, userinfo@host:port, absolute url")
+ << QUrl("path://user:password@host:3000") << "path://user:password@host:3000#anchor"
+ << QUrl("path://user:password@host:3000#anchor");
+
+ // Host syntax
+ // - We lose the port and the user info from the authority after navigation
+ QTest::newRow("Host syntax, host only, relative url")
+ << QUrl("host://host") << "#anchor" << QUrl("host://host/#anchor");
+ QTest::newRow("Host syntax, host only, absolute url")
+ << QUrl("host://host") << "host://host#anchor" << QUrl("host://host/#anchor");
+ QTest::newRow("Host syntax, host/path, relative url")
+ << QUrl("host://host/path") << "#anchor" << QUrl("host://host/path#anchor");
+ QTest::newRow("Host syntax, host/path, absolute url")
+ << QUrl("host://host/path") << "host://host/path#anchor"
+ << QUrl("host://host/path#anchor");
+ QTest::newRow("Host syntax, host:port, relative url")
+ << QUrl("host://host:3000") << "#anchor" << QUrl("host://host/#anchor");
+ QTest::newRow("Host syntax, host:port, absolute url")
+ << QUrl("host://host:3000") << "host://host:3000#anchor" << QUrl("host://host/#anchor");
+ QTest::newRow("Host syntax, userinfo@host:port, relative url")
+ << QUrl("host://user:password@host:3000") << "#anchor" << QUrl("host://host/#anchor");
+ QTest::newRow("Host syntax, userinfo@host:port, absolute url")
+ << QUrl("host://user:password@host:3000") << "host://user:password@host:3000#anchor"
+ << QUrl("host://host/#anchor");
+
+ // HostAndPort syntax
+ // - We lose the port and the user info from the authority after navigation
+ QTest::newRow("HostAndPort syntax, host only, relative url")
+ << QUrl("hostandport://host") << "#anchor" << QUrl("hostandport://host/#anchor");
+ QTest::newRow("HostAndPort syntax, host only, absolute url")
+ << QUrl("hostandport://host") << "hostandport://host#anchor"
+ << QUrl("hostandport://host/#anchor");
+ QTest::newRow("HostAndPort syntax, host/path, relative url")
+ << QUrl("hostandport://host/path") << "#anchor"
+ << QUrl("hostandport://host/path#anchor");
+ QTest::newRow("HostAndPort syntax, host/path, absolute url")
+ << QUrl("hostandport://host/path") << "hostandport://host/path#anchor"
+ << QUrl("hostandport://host/path#anchor");
+ QTest::newRow("HostAndPort syntax, host:port, relative url")
+ << QUrl("hostandport://host:3000") << "#anchor" << QUrl("hostandport://host/#anchor");
+ QTest::newRow("HostAndPort syntax, host:port, absolute url")
+ << QUrl("hostandport://host:3000") << "hostandport://host:3000#anchor"
+ << QUrl("hostandport://host/#anchor");
+ QTest::newRow("HostAndPort syntax, userinfo@host:port, relative url")
+ << QUrl("hostandport://user:password@host:3000") << "#anchor"
+ << QUrl("hostandport://host/#anchor");
+ QTest::newRow("HostAndPort syntax, userinfo@host:port, absolute url")
+ << QUrl("hostandport://user:password@host:3000")
+ << "hostandport://user:password@host:3000#anchor" << QUrl("hostandport://host/#anchor");
+
+ // HostPortAndUserInformation syntax
+ // - We lose the port and it preserves the user info in the authority after navigation
+ QTest::newRow("HostPortAndUserInformation syntax, host only, relative url")
+ << QUrl("hostportuserinfo://host") << "#anchor"
+ << QUrl("hostportuserinfo://host/#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, host only, absolute url")
+ << QUrl("hostportuserinfo://host") << "hostportuserinfo://host#anchor"
+ << QUrl("hostportuserinfo://host/#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, host/path, relative url")
+ << QUrl("hostportuserinfo://host/path") << "#anchor"
+ << QUrl("hostportuserinfo://host/path#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, host/path, absolute url")
+ << QUrl("hostportuserinfo://host/path") << "hostportuserinfo://host/path#anchor"
+ << QUrl("hostportuserinfo://host/path#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, host:port, relative url")
+ << QUrl("hostportuserinfo://host:3000") << "#anchor"
+ << QUrl("hostportuserinfo://host/#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, host:port, absolute url")
+ << QUrl("hostportuserinfo://host:3000") << "hostportuserinfo://host:3000#anchor"
+ << QUrl("hostportuserinfo://host/#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, userinfo@host:port, relative url")
+ << QUrl("hostportuserinfo://user:password@host:3000") << "#anchor"
+ << QUrl("hostportuserinfo://user:password@host/#anchor");
+ QTest::newRow("HostPortAndUserInformation syntax, userinfo@host:port, absolute url")
+ << QUrl("hostportuserinfo://user:password@host:3000")
+ << "hostportuserinfo://user:password@host:3000#anchor"
+ << QUrl("hostportuserinfo://user:password@host/#anchor");
+}
+
+void tst_Schemes::customSchemeFragmentNavigation()
+{
+ QFETCH(QUrl, baseUrl);
+ QFETCH(QUrl, expectedUrl);
+ QFETCH(QString, linkUrl);
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QWebEngineView view;
+ view.setPage(&page);
+ view.resize(800, 600);
+ view.show();
+ QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
+ QSignalSpy urlChangedSpy(&page, SIGNAL(urlChanged(QUrl)));
+
+ CustomScheme *schemeHandler = new CustomScheme(linkUrl);
+ page.profile()->installUrlSchemeHandler(baseUrl.scheme().toUtf8(), schemeHandler);
+
+ view.load(baseUrl);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.scrollY").toInt() == 0);
+
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link"));
+ QVERIFY(urlChangedSpy.wait());
+ QCOMPARE(page.url(), expectedUrl);
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.scrollY").toInt() > 0);
+
+ // Same document navigation doesn't emit loadFinished
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+}
+
QTEST_MAIN(tst_Schemes)
#include "tst_schemes.moc"
diff --git a/tests/auto/widgets/shutdown/CMakeLists.txt b/tests/auto/widgets/shutdown/CMakeLists.txt
new file mode 100644
index 000000000..e2ce9eeb9
--- /dev/null
+++ b/tests/auto/widgets/shutdown/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_shutdown
+ SOURCES
+ tst_shutdown.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+)
diff --git a/tests/auto/widgets/shutdown/shutdown.pro b/tests/auto/widgets/shutdown/shutdown.pro
deleted file mode 100644
index e99c7f493..000000000
--- a/tests/auto/widgets/shutdown/shutdown.pro
+++ /dev/null
@@ -1 +0,0 @@
-include(../tests.pri)
diff --git a/tests/auto/widgets/shutdown/tst_shutdown.cpp b/tests/auto/widgets/shutdown/tst_shutdown.cpp
index 5c1e426d2..c2b31bb80 100644
--- a/tests/auto/widgets/shutdown/tst_shutdown.cpp
+++ b/tests/auto/widgets/shutdown/tst_shutdown.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtTest/QtTest>
diff --git a/tests/auto/widgets/spellchecking/CMakeLists.txt b/tests/auto/widgets/spellchecking/CMakeLists.txt
new file mode 100644
index 000000000..d0c7656c1
--- /dev/null
+++ b/tests/auto/widgets/spellchecking/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+include(../../../../src/core/api/Qt6WebEngineCoreMacros.cmake)
+
+qt_internal_add_test(tst_spellchecking
+ SOURCES
+ tst_spellchecking.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+qt_internal_add_resource(tst_spellchecking "tst_spellchecking"
+ PREFIX
+ "/"
+ FILES
+ "resources/index.html"
+)
+
+file(GLOB_RECURSE dicts
+ ABSOLUTE ${CMAKE_CURRENT_LIST_DIR}/dict
+ *.dic
+)
+
+foreach(dictFile ${dicts})
+ qt_add_webengine_dictionary(
+ TARGET tst_spellchecking
+ SOURCE "${dictFile}"
+ OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+endforeach()
diff --git a/tests/auto/widgets/spellchecking/spellchecking.pro b/tests/auto/widgets/spellchecking/spellchecking.pro
deleted file mode 100644
index a36c82e20..000000000
--- a/tests/auto/widgets/spellchecking/spellchecking.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-include(../tests.pri)
-
-DISTFILES += \
- dict/en-US.dic \
- dict/en-US.aff \
- dict/de-DE.dic \
- dict/de-DE.aff \
-
-qtPrepareTool(CONVERT_TOOL, qwebengine_convert_dict)
-
-debug_and_release {
- CONFIG(debug, debug|release): DICTIONARIES_DIR = debug/qtwebengine_dictionaries
- else: DICTIONARIES_DIR = release/qtwebengine_dictionaries
-} else {
- DICTIONARIES_DIR = qtwebengine_dictionaries
-}
-
-dict.files = $$PWD/dict/en-US.dic $$PWD/dict/de-DE.dic
-dictoolbuild.input = dict.files
-dictoolbuild.output = $${DICTIONARIES_DIR}/${QMAKE_FILE_BASE}.bdic
-dictoolbuild.commands = $${CONVERT_TOOL} ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
-dictoolbuild.name = Build ${QMAKE_FILE_IN_BASE}
-dictoolbuild.CONFIG = no_link target_predeps
-QMAKE_EXTRA_COMPILERS += dictoolbuild
diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
index 801e2a76c..c643a56ba 100644
--- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
+++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
@@ -1,38 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "util.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <util.h>
#include <QtTest/QtTest>
-#include <QtWebEngineWidgets/qwebenginecontextmenudata.h>
-#include <QtWebEngineWidgets/qwebengineprofile.h>
-#include <QtWebEngineWidgets/qwebenginepage.h>
+#include <QtWebEngineCore/qwebenginecontextmenurequest.h>
+#include <QtWebEngineCore/qwebenginepage.h>
+#include <QtWebEngineCore/qwebengineprofile.h>
+#include <QtWebEngineCore/qwebenginesettings.h>
#include <QtWebEngineWidgets/qwebengineview.h>
-#include <qwebenginesettings.h>
class WebView : public QWebEngineView
{
@@ -47,22 +22,19 @@ public:
QTest::mouseRelease(widget, Qt::RightButton, {}, position);
}
- const QWebEngineContextMenuData& data()
- {
- return m_data;
- }
+ QWebEngineContextMenuRequest *data() { return m_data; }
signals:
void menuReady();
protected:
- void contextMenuEvent(QContextMenuEvent *)
+ void contextMenuEvent(QContextMenuEvent *) override
{
- m_data = page()->contextMenuData();
+ m_data = lastContextMenuRequest();
emit menuReady();
}
private:
- QWebEngineContextMenuData m_data;
+ QWebEngineContextMenuRequest *m_data;
};
class tst_Spellchecking : public QObject
@@ -173,19 +145,20 @@ void tst_Spellchecking::spellcheck()
QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lowe Qt ....','lowe');").toList();
QRect rect(list[0].value<int>(),list[1].value<int>(),list[2].value<int>(),list[3].value<int>());
+ QTRY_VERIFY(m_view->focusWidget());
//type text, spellchecker needs time
QTest::mouseMove(m_view->focusWidget(), 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++) {
+ for (int i = 0; i < text.size(); i++) {
QTest::keyClicks(m_view->focusWidget(), text.at(i));
QTest::qWait(60);
}
// make sure text is there
QString result = evaluateJavaScriptSync(m_view->page(), "text();").toString();
- QVERIFY(result == text);
+ QCOMPARE(result, text);
bool gotMisspelledWord = false; // clumsy QTRY_VERIFY still execs expr after first success
QString detail;
@@ -204,17 +177,17 @@ void tst_Spellchecking::spellcheck()
return false;
}
- if (!m_view->data().isValid()) {
+ if (!m_view->data()) {
detail = "invalid data";
return false;
}
- if (!m_view->data().isContentEditable()) {
+ if (!m_view->data()->isContentEditable()) {
detail = "content is not editable";
return false;
}
- if (m_view->data().misspelledWord().isEmpty()) {
+ if (m_view->data()->misspelledWord().isEmpty()) {
detail = "no misspelled word";
return false;
};
@@ -224,10 +197,10 @@ void tst_Spellchecking::spellcheck()
} (), qPrintable(QString("Context menu: %1").arg(detail)));
// check misspelled word
- QCOMPARE(m_view->data().misspelledWord(), QStringLiteral("lowe"));
+ QCOMPARE(m_view->data()->misspelledWord(), QStringLiteral("lowe"));
// check suggestions
- QCOMPARE(m_view->data().spellCheckerSuggestions(), suggestions);
+ QCOMPARE(m_view->data()->spellCheckerSuggestions(), suggestions);
// check replace word
m_view->page()->replaceMisspelledWord("love");
diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.qrc b/tests/auto/widgets/spellchecking/tst_spellchecking.qrc
deleted file mode 100644
index 505b932c7..000000000
--- a/tests/auto/widgets/spellchecking/tst_spellchecking.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>resources/index.html</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri
deleted file mode 100644
index 97954aedc..000000000
--- a/tests/auto/widgets/tests.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093
-QT_FOR_CONFIG += webenginecore-private
-
-TEMPLATE = app
-
-CONFIG += testcase
-CONFIG += c++14
-
-VPATH += $$_PRO_FILE_PWD_
-TARGET = tst_$$TARGET
-
-SOURCES += $${TARGET}.cpp
-INCLUDEPATH += $$PWD
-
-exists($$_PRO_FILE_PWD_/$${TARGET}.qrc): RESOURCES += $${TARGET}.qrc
-
-QT += testlib network webenginewidgets widgets quick quickwidgets
-
-# This define is used by some tests to look up resources in the source tree
-DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\"
-
-include(../embed_info_plist.pri)
diff --git a/tests/auto/widgets/touchinput/CMakeLists.txt b/tests/auto/widgets/touchinput/CMakeLists.txt
new file mode 100644
index 000000000..bd76666d6
--- /dev/null
+++ b/tests/auto/widgets/touchinput/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_touchinput
+ SOURCES
+ tst_touchinput.cpp
+ LIBRARIES
+ Qt::WebEngineWidgets
+ Qt::GuiPrivate
+ Test::Util
+)
diff --git a/tests/auto/widgets/touchinput/tst_touchinput.cpp b/tests/auto/widgets/touchinput/tst_touchinput.cpp
new file mode 100644
index 000000000..42178558c
--- /dev/null
+++ b/tests/auto/widgets/touchinput/tst_touchinput.cpp
@@ -0,0 +1,372 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <util.h>
+
+#include <QtGui/qpa/qwindowsysteminterface.h>
+#include <QSignalSpy>
+#include <QTest>
+#include <QPointingDevice>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+
+static QPointingDevice* s_touchDevice = nullptr;
+
+struct Page : QWebEnginePage
+{
+ QStringList alerts;
+ void javaScriptAlert(const QUrl &/*origin*/, const QString &msg) override { alerts.append(msg); }
+};
+
+class TouchInputTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+private Q_SLOTS:
+ void touchTap();
+ void touchTapAndHold();
+ void touchTapAndHoldCancelled();
+ void scrolling();
+ void pinchZoom_data();
+ void pinchZoom();
+ void complexSequence();
+ void buttonClickHandler();
+ void htmlSelectPopup();
+
+private:
+ Page page;
+ QWebEngineView view;
+ QSignalSpy loadSpy { &view, &QWebEngineView::loadFinished };
+ QPoint notextCenter, textCenter, inputCenter;
+
+ QString activeElement() { return evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(); }
+
+ void makeTouch(QWindow *w, const QPoint &p) {
+ QTest::touchEvent(w, s_touchDevice).press(1, p);
+ QTest::touchEvent(w, s_touchDevice).release(1, p);
+ }
+ void makeTouch(const QPoint &p) { makeTouch(view.windowHandle(), p); }
+
+ void gestureScroll(bool down) {
+ auto target = view.focusProxy();
+ QPoint p(target->width() / 2, target->height() / 4 * (down ? 3 : 1));
+
+ QTest::touchEvent(target, s_touchDevice).press(1, p, target);
+
+ QSignalSpy spy(view.page(), &QWebEnginePage::scrollPositionChanged);
+ for (int i = 0; i < 3; ++i) {
+ down ? p -= QPoint(5, 15) : p += QPoint(5, 15);
+ QTest::qWait(100); // too fast and events are recognized as fling gesture
+ QTest::touchEvent(target, s_touchDevice).move(1, p, target);
+ spy.wait();
+ }
+
+ QTest::touchEvent(target, s_touchDevice).release(1, p, target);
+ }
+
+ void gesturePinch(bool zoomIn, bool tapOneByOne = false) {
+ auto target = view.focusProxy();
+ QPoint p(target->width() / 2, target->height() / 2);
+ auto t1 = p - QPoint(zoomIn ? 50 : 150, 10), t2 = p + QPoint(zoomIn ? 50 : 150, 10);
+
+ if (tapOneByOne) {
+ QTest::touchEvent(target, s_touchDevice).press(0, t1, target);
+ QTest::touchEvent(target, s_touchDevice).stationary(0).press(1, t2, target);
+ } else {
+ QTest::touchEvent(target, s_touchDevice).press(0, t1, target).press(1, t2, target);
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ if (zoomIn) {
+ t1 -= QPoint(25, 5);
+ t2 += QPoint(25, 5);
+ } else {
+ t1 += QPoint(35, 5);
+ t2 -= QPoint(35, 5);
+ }
+ QTest::qWait(100); // too fast and events are recognized as fling gesture
+ QTest::touchEvent(target, s_touchDevice).move(1, t1, target).move(0, t2, target);
+ }
+
+ if (tapOneByOne) {
+ QTest::touchEvent(target, s_touchDevice).stationary(0).release(1, t2, target);
+ QTest::touchEvent(target, s_touchDevice).release(0, t1, target);
+ } else {
+ QTest::touchEvent(target, s_touchDevice).release(0, t1, target).release(1, t2, target);
+ }
+ }
+
+ int getScrollPosition(int *position = nullptr) {
+ int p = evaluateJavaScriptSync(view.page(), "window.scrollY").toInt();
+ return position ? (*position = p) : p;
+ }
+
+ int pageScrollPosition() {
+ // this one is updated later in page in asynchronous way
+ return qRound(view.page()->scrollPosition().y());
+ }
+
+ double getScaleFactor(double *scale = nullptr) {
+ double s = evaluateJavaScriptSync(view.page(), "window.visualViewport.scale").toDouble();
+ return scale ? (*scale = s) : s;
+ }
+};
+
+void TouchInputTest::initTestCase()
+{
+ s_touchDevice = QTest::createTouchDevice();
+
+ view.setPage(&page);
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+
+ view.show(); view.resize(480, 320);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ view.setHtml("<html><head><style>.rect { min-width: 240px; min-height: 120px; }</style></head><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' style='width: 150px;' type='text' value='The Qt Company2' /></form>"
+ "<button id='btn' type='button' onclick='alert(\"button clicked!\")'>Click Me!</button>"
+ "<select id='select' onchange='alert(\"option changed to: \" + this.value)'>"
+ "<option value='O1'>O1</option><option value='O2'>O2</option><option value='O3'>O3</option></select>"
+ "<table style='width: 100%; padding: 15px; text-align: center;'>"
+ "<tr><td>BEFORE</td><td><div class='rect' style='background-color: #00f;'></div></td><td>AFTER</td></tr>"
+ "<tr><td>BEFORE</td><td><div class='rect' style='background-color: #0f0;'></div></td><td>AFTER</td></tr>"
+ "<tr><td>BEFORE</td><td><div class='rect' style='background-color: #f00;'></div></td><td>AFTER</td></tr></table>"
+ "</body></html>");
+ QVERIFY(loadSpy.wait() && loadSpy.first().first().toBool());
+
+ notextCenter = elementCenter(view.page(), "notext");
+ textCenter = elementCenter(view.page(), "text");
+ inputCenter = elementCenter(view.page(), "input");
+}
+
+void TouchInputTest::init()
+{
+ QCOMPARE(activeElement(), QString());
+}
+
+void TouchInputTest::cleanup()
+{
+ evaluateJavaScriptSync(view.page(), "if (document.activeElement) document.activeElement.blur()");
+ evaluateJavaScriptSync(view.page(), "window.scrollTo(0, 0)");
+ QTRY_COMPARE(getScrollPosition(), 0);
+ QTRY_COMPARE(pageScrollPosition(), 0);
+ page.alerts.clear();
+}
+
+void TouchInputTest::touchTap()
+{
+ auto singleTap = [target = view.focusProxy()] (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(textCenter);
+ QTRY_COMPARE(activeElement(), QString());
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Single tap inside the input field focuses it without selecting the text
+ singleTap(inputCenter);
+ QTRY_COMPARE(activeElement(), QStringLiteral("input"));
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Single tap on the div clears the input field focus
+ singleTap(notextCenter);
+ QTRY_COMPARE(activeElement(), QString());
+
+ // Double tap on text still doesn't trigger a selection
+ singleTap(textCenter);
+ singleTap(textCenter);
+ QTRY_COMPARE(activeElement(), QString());
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Double tap inside the input field focuses it and selects the word under it
+ singleTap(inputCenter);
+ singleTap(inputCenter);
+ QTRY_COMPARE(activeElement(), 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(notextCenter);
+ singleTap(notextCenter);
+ QTRY_COMPARE(activeElement(), QString());
+ QTRY_VERIFY(!view.hasSelection());
+}
+
+void TouchInputTest::touchTapAndHold()
+{
+ auto tapAndHold = [target = view.focusProxy()] (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(textCenter);
+ QTRY_COMPARE(activeElement(), QString());
+ QTRY_COMPARE(view.selectedText(), QStringLiteral("Company"));
+
+ // Tap-and-hold inside the input field focuses it and selects the word under it
+ tapAndHold(inputCenter);
+ QTRY_COMPARE(activeElement(), 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(notextCenter);
+ QTRY_COMPARE(activeElement(), QString());
+ QTRY_VERIFY(!view.hasSelection());
+ QTRY_VERIFY(QApplication::activePopupWidget() != nullptr);
+
+ QApplication::activePopupWidget()->close();
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+#endif
+}
+
+void TouchInputTest::touchTapAndHoldCancelled()
+{
+ auto cancelledTapAndHold = [target = view.focusProxy()] (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(textCenter);
+ 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(inputCenter);
+ 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(notextCenter);
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+#endif
+}
+
+void TouchInputTest::scrolling()
+{
+ int p = getScrollPosition();
+ QCOMPARE(p, 0);
+
+ // scroll a bit down...
+ for (int i = 0; i < 3; ++i) {
+ gestureScroll(/* down = */true);
+ int positionBefore = p;
+ QTRY_VERIFY2(getScrollPosition(&p) > positionBefore, qPrintable(QString("i: %1, position: %2 -> %3").arg(i).arg(positionBefore).arg(p)));
+ }
+
+ // ... and then scroll page again but in opposite direction
+ for (int i = 0; i < 3; ++i) {
+ gestureScroll(/* down = */false);
+ int positionBefore = p;
+ QTRY_VERIFY2(getScrollPosition(&p) < positionBefore, qPrintable(QString("i: %1, position: %2 -> %3").arg(i).arg(positionBefore).arg(p)));
+ }
+
+ QTRY_COMPARE(getScrollPosition(), 0);
+}
+
+void TouchInputTest::pinchZoom_data()
+{
+ QTest::addColumn<bool>("tapOneByOne");
+ QTest::addRow("sequential") << true;
+ QTest::addRow("simultaneous") << false;
+}
+
+void TouchInputTest::pinchZoom()
+{
+ QFETCH(bool, tapOneByOne);
+ double scale = getScaleFactor();
+ QCOMPARE(scale, 1.0);
+
+ for (int i = 0; i < 3; ++i) {
+ gesturePinch(/* zoomIn = */true, tapOneByOne);
+ QTRY_VERIFY2(getScaleFactor(&scale) > 1.0, qPrintable(QString("i: %1, scale: %2").arg(i).arg(scale)));
+ gesturePinch(/* zoomIn = */false, tapOneByOne);
+ QTRY_COMPARE(getScaleFactor(&scale), 1.0);
+ }
+}
+
+void TouchInputTest::complexSequence()
+{
+ auto t = view.focusProxy();
+ QPoint pc(view.width() / 2, view.height() / 2), p1 = pc - QPoint(50, 25), p2 = pc + QPoint(50, 25);
+
+ for (int i = 0; i < 4; ++i) {
+ QTest::touchEvent(t, s_touchDevice).press(42, p1, t); QTest::qWait(50);
+ QTest::touchEvent(t, s_touchDevice).stationary(42).press(24, p2, t); QTest::qWait(50);
+ QTest::touchEvent(t, s_touchDevice).release(42, p1, t).release(24, p2, t);
+
+ // for additional variablity add zooming in on even steps and zooming out on odd steps
+ // MEMO scroll position will always be 0 while viewport scale factor > 1.0, so do zoom in after scroll
+ bool zoomIn = i % 2 == 0;
+
+ if (!zoomIn) {
+ gesturePinch(false);
+ QTRY_COMPARE(getScaleFactor(), 1.0);
+ }
+
+ int p = getScrollPosition(), positionBefore = p;
+ gestureScroll(true);
+ QTRY_VERIFY2_WITH_TIMEOUT(getScrollPosition(&p) > positionBefore, qPrintable(QString("i: %1, position: %2 -> %3").arg(i).arg(positionBefore).arg(p)), 1000);
+
+ if (zoomIn) {
+ double s = getScaleFactor(), scaleBefore = s;
+ gesturePinch(true);
+ QTRY_VERIFY2(getScaleFactor(&s) > scaleBefore, qPrintable(QString("i: %1, scale: %2").arg(i).arg(s)));
+ }
+ }
+}
+
+void TouchInputTest::buttonClickHandler()
+{
+ auto buttonCenter = elementGeometry(view.page(), "btn").center();
+ makeTouch(buttonCenter);
+ QTRY_VERIFY(!page.alerts.isEmpty());
+ QCOMPARE(page.alerts.first(), "button clicked!");
+ QCOMPARE(page.alerts.size(), 1);
+ QEXPECT_FAIL("", "Shouldn't trigger twice due to synthesized mouse events for touch", Continue);
+ QTRY_VERIFY_WITH_TIMEOUT(page.alerts.size() == 2, 500);
+}
+
+void TouchInputTest::htmlSelectPopup()
+{
+ auto selectRect = elementGeometry(view.page(), "select");
+ makeTouch(selectRect.center());
+ QTRY_VERIFY(QApplication::activePopupWidget());
+ QCOMPARE(activeElement(), QStringLiteral("select"));
+
+ auto popup = QApplication::activePopupWidget();
+ makeTouch(popup->windowHandle(), QPoint(popup->width() / 2, popup->height() / 2));
+ QTRY_VERIFY(!QApplication::activePopupWidget());
+
+ QTRY_VERIFY(!page.alerts.isEmpty());
+ QCOMPARE(page.alerts.first(), "option changed to: O2");
+ QEXPECT_FAIL("", "Shouldn't trigger twice due to synthesized mouse events for touch", Continue);
+ QTRY_VERIFY_WITH_TIMEOUT(page.alerts.size() == 2, 500);
+}
+
+QTEST_MAIN(TouchInputTest)
+#include "tst_touchinput.moc"
diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h
deleted file mode 100644
index cb58f4243..000000000
--- a/tests/auto/widgets/util.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// Functions and macros that really need to be in QTestLib
-
-#if 0
-#pragma qt_no_master_include
-#endif
-
-#include <QEventLoop>
-#include <QSignalSpy>
-#include <QTimer>
-#include <qwebenginepage.h>
-#include <qwebengineview.h>
-
-#if !defined(TESTS_SOURCE_DIR)
-#define TESTS_SOURCE_DIR ""
-#endif
-
-/**
- * Just like QSignalSpy but facilitates sync and async
- * signal emission. For example if you want to verify that
- * page->foo() emitted a signal, it could be that the
- * implementation decides to emit the signal asynchronously
- * - in which case we want to spin a local event loop until
- * emission - or that the call to foo() emits it right away.
- */
-class SignalBarrier : private QSignalSpy
-{
-public:
- SignalBarrier(const QObject* obj, const char* aSignal)
- : QSignalSpy(obj, aSignal)
- { }
-
- bool ensureSignalEmitted()
- {
- bool result = count() > 0;
- if (!result)
- result = wait();
- clear();
- return result;
- }
-};
-
-template<typename T, typename R>
-struct CallbackWrapper {
- QPointer<R> p;
- void operator()(const T& result) {
- if (p)
- (*p)(result);
- }
-};
-
-template<typename T>
-class CallbackSpy: public QObject {
-public:
- CallbackSpy() : called(false) {
- timeoutTimer.setSingleShot(true);
- QObject::connect(&timeoutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
- }
-
- T waitForResult(int timeout = 20000) {
- const int step = 1000;
- int elapsed = 0;
- while (elapsed < timeout && !called) {
- timeoutTimer.start(step);
- eventLoop.exec();
- elapsed += step;
- }
- return result;
- }
-
- bool wasCalled() const {
- return called;
- }
-
- void operator()(const T &result) {
- this->result = result;
- called = true;
- eventLoop.quit();
- }
-
- CallbackWrapper<T, CallbackSpy<T> > ref()
- {
- CallbackWrapper<T, CallbackSpy<T> > wrapper = {this};
- return wrapper;
- }
-
-private:
- Q_DISABLE_COPY(CallbackSpy)
- bool called;
- QTimer timeoutTimer;
- QEventLoop eventLoop;
- T result;
-};
-
-static inline QString toPlainTextSync(QWebEnginePage *page)
-{
- CallbackSpy<QString> spy;
- page->toPlainText(spy.ref());
- return spy.waitForResult();
-}
-
-static inline QString toHtmlSync(QWebEnginePage *page)
-{
- CallbackSpy<QString> spy;
- page->toHtml(spy.ref());
- return spy.waitForResult();
-}
-
-static inline bool findTextSync(QWebEnginePage *page, const QString &subString)
-{
- CallbackSpy<bool> spy;
- page->findText(subString, {}, spy.ref());
- return spy.waitForResult();
-}
-
-static inline QVariant evaluateJavaScriptSync(QWebEnginePage *page, const QString &script)
-{
- CallbackSpy<QVariant> spy;
- page->runJavaScript(script, spy.ref());
- return spy.waitForResult();
-}
-
-static inline QVariant evaluateJavaScriptSyncInWorld(QWebEnginePage *page, const QString &script, int worldId)
-{
- CallbackSpy<QVariant> spy;
- page->runJavaScript(script, worldId, spy.ref());
- return spy.waitForResult();
-}
-
-static inline QUrl baseUrlSync(QWebEnginePage *page)
-{
- CallbackSpy<QVariant> spy;
- page->runJavaScript("document.baseURI", spy.ref());
- return spy.waitForResult().toUrl();
-}
-
-static inline bool loadSync(QWebEnginePage *page, const QUrl &url, bool ok = true)
-{
- QSignalSpy spy(page, &QWebEnginePage::loadFinished);
- page->load(url);
- return (!spy.empty() || spy.wait(20000)) && (spy.front().value(0).toBool() == ok);
-}
-
-static inline bool loadSync(QWebEngineView *view, const QUrl &url, bool ok = true)
-{
- return loadSync(view->page(), url, ok);
-}
-
-#define W_QSKIP(a, b) QSKIP(a)
-
-#define W_QTEST_MAIN(TestObject, params) \
-int main(int argc, char *argv[]) \
-{ \
- QVector<const char *> w_argv(argc); \
- for (int i = 0; i < argc; ++i) \
- w_argv[i] = argv[i]; \
- for (int i = 0; i < params.size(); ++i) \
- w_argv.append(params[i].data()); \
- int w_argc = w_argv.size(); \
- \
- QApplication app(w_argc, const_cast<char **>(w_argv.data())); \
- app.setAttribute(Qt::AA_Use96Dpi, true); \
- QTEST_DISABLE_KEYPAD_NAVIGATION \
- TestObject tc; \
- QTEST_SET_MAIN_SOURCE_PATH \
- return QTest::qExec(&tc, argc, argv); \
-}
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
deleted file mode 100644
index 6d65eecb5..000000000
--- a/tests/auto/widgets/widgets.pro
+++ /dev/null
@@ -1,51 +0,0 @@
-include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093
-QT_FOR_CONFIG += webenginecore webenginecore-private
-
-TEMPLATE = subdirs
-
-SUBDIRS += \
- defaultsurfaceformat \
- devtools \
- faviconmanager \
- loadsignals \
- offscreen \
- origins \
- proxy \
- proxypac \
- schemes \
- shutdown \
- qwebenginedownloaditem \
- qwebenginepage \
- qwebenginehistory \
- qwebengineprofile \
- qwebenginescript \
- qwebenginesettings \
- qwebengineview
-
-qtConfig(accessibility) {
- SUBDIRS += accessibility
-}
-
-qtConfig(webengine-printing-and-pdf) {
- SUBDIRS += printing
-}
-
-qtConfig(ssl) {
- SUBDIRS += certificateerror
-}
-
-qtConfig(webengine-spellchecker):!cross_compile {
- !qtConfig(webengine-native-spellchecker) {
- SUBDIRS += spellchecking
- } else {
- message("Spellcheck test will not be built because it depends on usage of Hunspell dictionaries.")
- }
-}
-
-# QTBUG-60268
-boot2qt: SUBDIRS -= accessibility defaultsurfaceformat devtools \
- qwebenginepage \
- qwebengineprofile \
- qwebengineview
-
-win32: SUBDIRS -= offscreen