summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/quick/qmltests/data/script-with-bad-match-metadata.js9
-rw-r--r--tests/auto/quick/qmltests/data/tst_userScripts.qml17
-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/serviceWorker.html14
-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/tst_origins.cpp72
-rw-r--r--tests/auto/widgets/origins/tst_origins.qrc6
-rw-r--r--tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp1
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp19
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp178
13 files changed, 360 insertions, 2 deletions
diff --git a/tests/auto/quick/qmltests/data/script-with-bad-match-metadata.js b/tests/auto/quick/qmltests/data/script-with-bad-match-metadata.js
new file mode 100644
index 000000000..c9a811e5c
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/script-with-bad-match-metadata.js
@@ -0,0 +1,9 @@
+// ==UserScript==
+// @name Test bad match script
+// @homepageURL http://www.qt.io/
+// @description Test script with metadata block with an invalid match directive
+// @match some:junk
+// @run-at document-end
+// ==/UserScript==
+
+document.title = "New title for some:junk";
diff --git a/tests/auto/quick/qmltests/data/tst_userScripts.qml b/tests/auto/quick/qmltests/data/tst_userScripts.qml
index d7c7d5983..f4fcc30ab 100644
--- a/tests/auto/quick/qmltests/data/tst_userScripts.qml
+++ b/tests/auto/quick/qmltests/data/tst_userScripts.qml
@@ -54,6 +54,11 @@ Item {
sourceUrl: Qt.resolvedUrl("script-with-metadata.js")
}
+ WebEngineScript {
+ id: scriptWithBadMatchMetadata
+ sourceUrl: Qt.resolvedUrl("script-with-bad-match-metadata.js")
+ }
+
TestWebEngineView {
id: webEngineView
width: 400
@@ -191,6 +196,18 @@ Item {
tryCompare(webEngineView, "title", "Test page with huge link area and iframe");
}
+ function test_dontInjectBadUrlPatternsEverywhere() {
+ compare(scriptWithBadMatchMetadata.name, "Test bad match script");
+ compare(scriptWithBadMatchMetadata.injectionPoint, WebEngineScript.DocumentReady);
+
+ webEngineView.userScripts = [ scriptWithBadMatchMetadata ];
+
+ // @match some:junk
+ webEngineView.url = Qt.resolvedUrl("test2.html");
+ webEngineView.waitForLoadSucceeded();
+ tryCompare(webEngineView, "title", "Test page with huge link area");
+ }
+
function test_profileWideScript() {
webEngineView.profile.userScripts = [ changeDocumentTitleScript ];
diff --git a/tests/auto/widgets/origins/resources/dedicatedWorker.html b/tests/auto/widgets/origins/resources/dedicatedWorker.html
new file mode 100644
index 000000000..cb4f14e73
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/dedicatedWorker.html
@@ -0,0 +1,19 @@
+<!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
new file mode 100644
index 000000000..2631939d7
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/dedicatedWorker.js
@@ -0,0 +1 @@
+onmessage = (e) => { postMessage(e.data + 1); };
diff --git a/tests/auto/widgets/origins/resources/serviceWorker.html b/tests/auto/widgets/origins/resources/serviceWorker.html
new file mode 100644
index 000000000..b2bdc8c60
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/serviceWorker.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>serviceWorker</title>
+ <script>
+ var done = false;
+ var error;
+ navigator.serviceWorker.register("serviceWorker.js")
+ .then((r) => { done = true; })
+ .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
new file mode 100644
index 000000000..40a8c178f
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/serviceWorker.js
@@ -0,0 +1 @@
+/* empty */
diff --git a/tests/auto/widgets/origins/resources/sharedWorker.html b/tests/auto/widgets/origins/resources/sharedWorker.html
new file mode 100644
index 000000000..8b5a0a794
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/sharedWorker.html
@@ -0,0 +1,19 @@
+<!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
new file mode 100644
index 000000000..60ef93a5f
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/sharedWorker.js
@@ -0,0 +1,6 @@
+onconnect = function(e) {
+ let port = e.ports[0];
+ port.onmessage = function(e) {
+ port.postMessage(e.data + 1);
+ };
+};
diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp
index 5c798ddc2..61d54e6de 100644
--- a/tests/auto/widgets/origins/tst_origins.cpp
+++ b/tests/auto/widgets/origins/tst_origins.cpp
@@ -73,6 +73,9 @@ private Q_SLOTS:
void subdirWithoutAccess();
void mixedSchemes();
void webSocket();
+ void dedicatedWorker();
+ void sharedWorker();
+ void serviceWorker();
private:
bool load(const QUrl &url)
@@ -259,9 +262,74 @@ void tst_Origins::webSocket()
QVERIFY(load(QSL("qrc:/resources/websocket.html")));
QTRY_VERIFY(eval(QSL("err")) == QVariant(expected));
+ QVERIFY(load(QSL("tst:/resources/websocket.html")));
+ QTRY_VERIFY(eval(QSL("err")) == QVariant(expected));
+}
+
+// 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(load(QSL("file:" THIS_DIR "resources/dedicatedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QCOMPARE(eval(QSL("result")), QVariant(42));
+
+ QVERIFY(load(QSL("qrc:/resources/dedicatedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QCOMPARE(eval(QSL("result")), QVariant(42));
+
// FIXME(juvaldma): QTBUG-62536
- // QVERIFY(load(QSL("tst:/resources/websocket.html")));
- // QTRY_VERIFY(eval(QSL("err")) == QVariant(expected));
+ QVERIFY(load(QSL("tst:/resources/dedicatedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QVERIFY(eval(QSL("error")).toString()
+ .contains(QSL("Access to dedicated workers is denied to origin 'tst://'")));
+}
+
+// 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(load(QSL("file:" THIS_DIR "resources/sharedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QVERIFY(eval(QSL("error")).toString()
+ .contains(QSL("cannot be accessed from origin 'null'")));
+ }
+
+ {
+ ScopedAttribute sa(m_page.settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true);
+ QVERIFY(load(QSL("file:" THIS_DIR "resources/sharedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QCOMPARE(eval(QSL("result")), QVariant(42));
+ }
+
+ QVERIFY(load(QSL("qrc:/resources/sharedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QCOMPARE(eval(QSL("result")), QVariant(42));
+
+ QVERIFY(load(QSL("tst:/resources/sharedWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QCOMPARE(eval(QSL("result")), QVariant(42));
+}
+
+// Service workers don't work.
+void tst_Origins::serviceWorker()
+{
+ QVERIFY(load(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(load(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(load(QSL("tst:/resources/serviceWorker.html")));
+ QTRY_VERIFY(eval(QSL("done")).toBool());
+ QVERIFY(eval(QSL("error")).toString()
+ .contains(QSL("Only secure origins are allowed")));
}
QTEST_MAIN(tst_Origins)
diff --git a/tests/auto/widgets/origins/tst_origins.qrc b/tests/auto/widgets/origins/tst_origins.qrc
index 47be3bd0d..fbbbef139 100644
--- a/tests/auto/widgets/origins/tst_origins.qrc
+++ b/tests/auto/widgets/origins/tst_origins.qrc
@@ -1,9 +1,15 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
+ <file>resources/dedicatedWorker.html</file>
+ <file>resources/dedicatedWorker.js</file>
<file>resources/mixed_frame.html</file>
<file>resources/mixed_qrc.html</file>
<file>resources/mixed_tst.html</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>
diff --git a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp b/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
index 4848038df..f932d50c3 100644
--- a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
+++ b/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
@@ -112,6 +112,7 @@ void tst_QWebEngineDownloads::initTestCase()
m_page = new QWebEnginePage(m_profile);
m_view = new QWebEngineView;
m_view->setPage(m_page);
+ m_view->resize(640, 480);
m_view->show();
}
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index ee7f9b2c2..025df76c7 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -2878,6 +2878,12 @@ void tst_QWebEnginePage::urlChange()
QTRY_COMPARE(urlSpy.size(), 1);
QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), dataUrl2);
+
+ QUrl testUrl("http://test.qt.io/");
+ m_view->setHtml(QStringLiteral("<h1>Test</h1"), testUrl);
+
+ QTRY_COMPARE(urlSpy.size(), 1);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), testUrl);
}
class FakeReply : public QNetworkReply {
@@ -3307,6 +3313,7 @@ protected:
void tst_QWebEnginePage::evaluateWillCauseRepaint()
{
WebView view;
+ view.resize(640, 480);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -4047,6 +4054,7 @@ void tst_QWebEnginePage::mouseButtonTranslation()
<div style=\"height:600px;\" onmousedown=\"saveLastEvent(event)\">\
</div>\
</body></html>"));
+ view.resize(640, 480);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
QTRY_VERIFY(spy.count() == 1);
@@ -4071,6 +4079,7 @@ void tst_QWebEnginePage::mouseMovementProperties()
QWebEngineView view;
ConsolePage page;
view.setPage(&page);
+ view.resize(640, 480);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -4311,6 +4320,16 @@ void tst_QWebEnginePage::dataURLFragment()
QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, 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);
+
+ QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, elementCenter(m_page, "link"));
+ QVERIFY(urlChangedSpy.wait());
+ QCOMPARE(m_page->url(), QUrl("http://test.qt.io/mytest.html#anchor"));
}
void tst_QWebEnginePage::devTools()
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 207836bef..248d906ef 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -153,6 +153,7 @@ private Q_SLOTS:
void focusOnNavigation_data();
void focusOnNavigation();
void focusInternalRenderWidgetHostViewQuickItem();
+ void doNotBreakLayout();
void changeLocale();
void inputMethodsTextFormat_data();
@@ -173,6 +174,7 @@ private Q_SLOTS:
void imeCompositionQueryEvent_data();
void imeCompositionQueryEvent();
void newlineInTextarea();
+ void imeJSInputEvents();
void mouseLeave();
@@ -344,6 +346,7 @@ void tst_QWebEngineView::crashTests()
void tst_QWebEngineView::microFocusCoordinates()
{
QWebEngineView webView;
+ webView.resize(640, 480);
webView.show();
QVERIFY(QTest::qWaitForWindowExposed(&webView));
@@ -378,6 +381,7 @@ void tst_QWebEngineView::focusInputTypes()
bool imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability);
QWebEngineView webView;
+ webView.resize(640, 480);
webView.show();
QVERIFY(QTest::qWaitForWindowExposed(&webView));
@@ -481,6 +485,7 @@ void tst_QWebEngineView::unhandledKeyEventPropagation()
{
KeyEventRecordingWidget parentWidget;
QWebEngineView webView(&parentWidget);
+ webView.resize(640, 480);
parentWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&webView));
@@ -824,6 +829,7 @@ void tst_QWebEngineView::doNotSendMouseKeyboardEventsWhenDisabled()
QFETCH(int, resultEventCount);
KeyboardAndMouseEventRecordingWidget parentWidget;
+ parentWidget.resize(640, 480);
QWebEngineView webView(&parentWidget);
webView.setEnabled(viewEnabled);
parentWidget.setLayout(new QStackedLayout);
@@ -1029,6 +1035,31 @@ void tst_QWebEngineView::focusInternalRenderWidgetHostViewQuickItem()
QTRY_COMPARE(renderWidgetHostViewQuickItem->hasFocus(), true);
}
+void tst_QWebEngineView::doNotBreakLayout()
+{
+ QScopedPointer<QWidget> containerWidget(new QWidget);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(new QWidget);
+ layout->addWidget(new QWidget);
+ layout->addWidget(new QWidget);
+ layout->addWidget(new QWebEngineView);
+
+ containerWidget->setLayout(layout);
+ containerWidget->setGeometry(50, 50, 800, 600);
+ containerWidget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data()));
+
+ QSize previousSize = static_cast<QWidgetItem *>(layout->itemAt(0))->widget()->size();
+ for (int i = 1; i < layout->count(); i++) {
+ QSize actualSize = static_cast<QWidgetItem *>(layout->itemAt(i))->widget()->size();
+ // There could be smaller differences on some platforms
+ QVERIFY(qAbs(previousSize.width() - actualSize.width()) <= 2);
+ QVERIFY(qAbs(previousSize.height() - actualSize.height()) <= 2);
+ previousSize = actualSize;
+ }
+}
+
void tst_QWebEngineView::changeLocale()
{
QStringList errorLines;
@@ -1592,6 +1623,7 @@ void tst_QWebEngineView::softwareInputPanel()
{
TestInputContext testContext;
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
@@ -1648,6 +1680,7 @@ void tst_QWebEngineView::softwareInputPanel()
void tst_QWebEngineView::inputMethods()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -1744,6 +1777,7 @@ void tst_QWebEngineView::inputMethods()
void tst_QWebEngineView::textSelectionInInputField()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -1825,6 +1859,7 @@ void tst_QWebEngineView::textSelectionInInputField()
void tst_QWebEngineView::textSelectionOutOfInputField()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -1908,6 +1943,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
void tst_QWebEngineView::hiddenText()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
@@ -1933,6 +1969,7 @@ void tst_QWebEngineView::hiddenText()
void tst_QWebEngineView::emptyInputMethodEvent()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -1979,6 +2016,7 @@ void tst_QWebEngineView::emptyInputMethodEvent()
void tst_QWebEngineView::imeComposition()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -2153,6 +2191,7 @@ void tst_QWebEngineView::imeComposition()
void tst_QWebEngineView::newlineInTextarea()
{
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
@@ -2249,6 +2288,142 @@ void tst_QWebEngineView::newlineInTextarea()
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line"));
}
+void tst_QWebEngineView::imeJSInputEvents()
+{
+ QWebEngineView view;
+ view.resize(640, 480);
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+ view.show();
+
+ auto logLines = [&view]() -> QStringList {
+ return evaluateJavaScriptSync(view.page(), "log.textContent").toString().split("\n").filter(QRegExp(".+"));
+ };
+
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.page()->setHtml("<html>"
+ "<head><script>"
+ " var input, log;"
+ " function verboseEvent(ev) {"
+ " log.textContent += ev + ' ' + ev.type + ' ' + ev.data + '\\n';"
+ " }"
+ " function clear(ev) {"
+ " log.textContent = '';"
+ " input.textContent = '';"
+ " }"
+ " function init() {"
+ " input = document.getElementById('input');"
+ " log = document.getElementById('log');"
+ " events = [ 'textInput', 'beforeinput', 'input', 'compositionstart', 'compositionupdate', 'compositionend' ];"
+ " for (var e in events)"
+ " input.addEventListener(events[e], verboseEvent);"
+ " }"
+ "</script></head>"
+ "<body onload='init()'>"
+ " <div id='input' contenteditable='true' style='border-style: solid;'></div>"
+ " <pre id='log'></pre>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ evaluateJavaScriptSync(view.page(), "document.getElementById('input').focus()");
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+
+ // 1. Commit text (this is how dead keys work on Linux).
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("commit");
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ // Simply committing text should not trigger any JS composition event.
+ QTRY_COMPARE(logLines().count(), 3);
+ QCOMPARE(logLines()[0], "[object InputEvent] beforeinput commit");
+ QCOMPARE(logLines()[1], "[object TextEvent] textInput commit");
+ QCOMPARE(logLines()[2], "[object InputEvent] input commit");
+
+ evaluateJavaScriptSync(view.page(), "clear()");
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "log.textContent + input.textContent").toString().isEmpty());
+
+ // 2. Start composition then commit text (this is how dead keys work on macOS).
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("preedit", attributes);
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ QTRY_COMPARE(logLines().count(), 4);
+ QCOMPARE(logLines()[0], "[object CompositionEvent] compositionstart ");
+ QCOMPARE(logLines()[1], "[object InputEvent] beforeinput preedit");
+ QCOMPARE(logLines()[2], "[object CompositionEvent] compositionupdate preedit");
+ QCOMPARE(logLines()[3], "[object InputEvent] input preedit");
+
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("commit");
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ QTRY_COMPARE(logLines().count(), 9);
+ QCOMPARE(logLines()[4], "[object InputEvent] beforeinput commit");
+ QCOMPARE(logLines()[5], "[object CompositionEvent] compositionupdate commit");
+ QCOMPARE(logLines()[6], "[object TextEvent] textInput commit");
+ QCOMPARE(logLines()[7], "[object InputEvent] input commit");
+ QCOMPARE(logLines()[8], "[object CompositionEvent] compositionend commit");
+
+ evaluateJavaScriptSync(view.page(), "clear()");
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "log.textContent + input.textContent").toString().isEmpty());
+
+ // 3. Start composition then cancel it with an empty IME event.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("preedit", attributes);
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ QTRY_COMPARE(logLines().count(), 4);
+ QCOMPARE(logLines()[0], "[object CompositionEvent] compositionstart ");
+ QCOMPARE(logLines()[1], "[object InputEvent] beforeinput preedit");
+ QCOMPARE(logLines()[2], "[object CompositionEvent] compositionupdate preedit");
+ QCOMPARE(logLines()[3], "[object InputEvent] input preedit");
+
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ QTRY_COMPARE(logLines().count(), 9);
+ QCOMPARE(logLines()[4], "[object InputEvent] beforeinput ");
+ QCOMPARE(logLines()[5], "[object CompositionEvent] compositionupdate ");
+ QCOMPARE(logLines()[6], "[object TextEvent] textInput ");
+ QCOMPARE(logLines()[7], "[object InputEvent] input null");
+ QCOMPARE(logLines()[8], "[object CompositionEvent] compositionend ");
+
+ evaluateJavaScriptSync(view.page(), "clear()");
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "log.textContent + input.textContent").toString().isEmpty());
+
+ // 4. Send empty IME event.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ QApplication::sendEvent(view.focusProxy(), &event);
+ qApp->processEvents();
+ }
+
+ // No JS event is expected.
+ QTest::qWait(100);
+ QVERIFY(logLines().isEmpty());
+
+ evaluateJavaScriptSync(view.page(), "clear()");
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "log.textContent + input.textContent").toString().isEmpty());
+}
+
void tst_QWebEngineView::imeCompositionQueryEvent_data()
{
QTest::addColumn<QString>("receiverObjectName");
@@ -2260,6 +2435,7 @@ void tst_QWebEngineView::imeCompositionQueryEvent_data()
void tst_QWebEngineView::imeCompositionQueryEvent()
{
QWebEngineView view;
+ view.resize(640, 480);
view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
view.show();
@@ -2341,6 +2517,7 @@ void tst_QWebEngineView::globalMouseSelection()
QApplication::clipboard()->clear(QClipboard::Selection);
QWebEngineView view;
+ view.resize(640, 480);
view.show();
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
@@ -2421,6 +2598,7 @@ void tst_QWebEngineView::contextMenu()
}
view.setContextMenuPolicy(contextMenuPolicy);
+ view.resize(640, 480);
view.show();
QVERIFY(view.findChildren<QMenu *>().isEmpty());