diff --git a/tests/auto/quick/qmltests/data/keyboardEvents.html b/tests/auto/quick/qmltests/data/keyboardEvents.html new file mode 100644 index 0000000000000000000000000000000000000000..d536d849fe5d9f15b4bb50e44ab5e4c26bc5b727 --- /dev/null +++ b/tests/auto/quick/qmltests/data/keyboardEvents.html @@ -0,0 +1,98 @@ +<html> +<head> + <style> + div { + width: 300px; + margin-bottom: 10px; + } + + #div_container { + display: inline-block; + } + + #div_container div { + width: 100px; + height: 100px; + border: 2px solid black; + padding: 10px; + margin: 0 10px 0 10px; + float: left; + } + + #div_container div:focus { + border: 2px solid red; + } + + #form_container span { + display: block; + padding-bottom: 10px; + } + + #form_container label { + float: left; + text-align: right; + width: 50px; + margin-right: 20px; + } + </style> +</head> + +<body onload="document.getElementById('first_div').focus()"> + <div id="div_container"> + <div id="first_div" tabindex="0">First</div> + <div id="second_div" tabindex="0">Second</div> + </div> + + <div id="form_container"> + <form><fieldset> + <legend>Form</legend> + + <span> + <label for="text_input">text</label> + <input id="text_input" type="text" /> + </span> + + <span> + <input id="radio1" type="radio" name="radio">radio1</input> + <input id="radio2" type="radio" name="radio">radio2</input> + </span> + + <span> + <input id="checkbox1" type="checkbox" name="checkbox1" checked="true">checkbox1</input> + <input id="checkbox2" type="checkbox" name="checkbox2" checked="true">checkbox2</input> + </span> + + <span> + <label for="number_input">number</label> + <input id="number_input" type="number" min="0" max="10" value="5" /> + </span> + + <span> + <label for="range_input">range</label> + <input id="range_input" type="range" min="0" max="10" value="5" /> + </span> + + <span> + <label for="search_input">search</label> + <input id="search_input" type="search" value="test" /> + </span> + + <input id="submit_button" type="submit" value="Submit" /> + </fieldset></form> + </div> + + <div> + <select id="combobox"> + <option value="a">a</option> + <option value="b">b</option> + <option value="c">c</option> + </select> + </div> + + <div> + <a id="first_hyperlink" href="">First</a> + <br /> + <a id="second_hyperlink" href="">Second</a> + </div> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml new file mode 100644 index 0000000000000000000000000000000000000000..7007a85ac1a4b776241227f75abd6b07fcd26051 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.4 + +TestWebEngineView { + id: webEngineView + width: 350 + height: 480 + + TestCase { + name: "WebEngineViewKeyboardEvents" + when: windowShown + + function getActiveElementId() { + var activeElementId; + runJavaScript("document.activeElement.id", function(result) { + activeElementId = result; + }); + tryVerify(function() { return activeElementId != undefined }); + return activeElementId; + } + + function verifyElementHasFocus(element) { + tryVerify(function() { return getActiveElementId() == element; }, 5000, + "Element \"" + element + "\" has focus"); + + } + + function setFocusToElement(element) { + runJavaScript("document.getElementById('" + element + "').focus()"); + verifyElementHasFocus(element); + } + + function isElementChecked(element) { + var elementChecked; + runJavaScript("document.getElementById('" + element + "').checked", function(result) { + elementChecked = result; + }); + tryVerify(function() { return elementChecked != undefined; }); + return elementChecked; + } + + function verifyElementChecked(element, expected) { + tryVerify(function() { return expected == isElementChecked(element); }, 5000, + "Element \"" + element + "\" is " + (expected ? "" : "not") + " checked"); + } + + function getElementValue(element) { + var elementValue; + runJavaScript("document.getElementById('" + element + "').value", function(result) { + elementValue = result; + }); + tryVerify(function() { return elementValue != undefined; }); + return elementValue; + } + + function compareElementValue(element, expected) { + tryVerify(function() { return expected == getElementValue(element); }, 5000, + "Value of element \"" + element + "\" is \"" + expected + "\""); + } + + function test_keyboardEvents() { + webEngineView.url = Qt.resolvedUrl("keyboardEvents.html"); + verify(webEngineView.waitForLoadSucceeded()); + + var elements = [ + "first_div", "second_div", + "text_input", "radio1", "checkbox1", "checkbox2", + "number_input", "range_input", "search_input", + "submit_button", "combobox", "first_hyperlink", "second_hyperlink" + ]; + + // Iterate over the elements of the test page with the Tab key. This tests whether any + // element blocks the in-page navigation by Tab. + for (var i = 0; i < elements.length; ++i) { + verifyElementHasFocus(elements[i]) + keyPress(Qt.Key_Tab); + } + + // Move back to the radio buttons with the Shift+Tab key combination + for (var i = 0; i < 10; ++i) + keyPress(Qt.Key_Tab, Qt.ShiftModifier); + verifyElementHasFocus("radio2"); + + // Test the Space key by checking a radio button + verifyElementChecked("radio2", false); + keyClick(Qt.Key_Space); + verifyElementChecked("radio2", true); + + // Test the Left key by switching the radio button + verifyElementChecked("radio1", false); + keyPress(Qt.Key_Left); + verifyElementHasFocus("radio1"); + verifyElementChecked("radio1", true); + + // Test the Space key by unchecking a checkbox + setFocusToElement("checkbox1"); + verifyElementChecked("checkbox1", true); + keyClick(Qt.Key_Space); + verifyElementChecked("checkbox1", false); + + // Test the Up and Down keys by changing the value of a spinbox + setFocusToElement("number_input"); + compareElementValue("number_input", 5); + keyPress(Qt.Key_Up); + compareElementValue("number_input", 6); + keyPress(Qt.Key_Down); + compareElementValue("number_input", 5); + + // Test the Left, Right, Home, PageUp, End and PageDown keys by changing the value of a slider + setFocusToElement("range_input"); + compareElementValue("range_input", 5); + keyPress(Qt.Key_Left); + compareElementValue("range_input", 4); + keyPress(Qt.Key_Right); + compareElementValue("range_input", 5); + keyPress(Qt.Key_Home); + compareElementValue("range_input", 0); + keyPress(Qt.Key_PageUp); + compareElementValue("range_input", 1); + keyPress(Qt.Key_End); + compareElementValue("range_input", 10); + keyPress(Qt.Key_PageDown); + compareElementValue("range_input", 9); + + // Test the Escape key by removing the content of a search field + setFocusToElement("search_input"); + compareElementValue("search_input", "test"); + keyPress(Qt.Key_Escape); + compareElementValue("search_input", ""); + + // Test the alpha keys by changing the values in a combobox + setFocusToElement("combobox"); + compareElementValue("combobox", "a"); + keyPress(Qt.Key_B); + compareElementValue("combobox", "b"); + // Must wait with the second key press to simulate selection of another element + wait(1000); + keyPress(Qt.Key_C); + compareElementValue("combobox", "c"); + + // Test the Enter key by loading a page with a hyperlink + setFocusToElement("first_hyperlink"); + keyPress(Qt.Key_Enter); + verify(webEngineView.waitForLoadSucceeded()); + } + } +} diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 726519db2aa95efb995707067ea52c3e7f2b5f27..4d4268324a5ea3be9a95c4b806cee275ac768ac7 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -39,6 +39,7 @@ OTHER_FILES += \ $$PWD/data/test3.html \ $$PWD/data/test4.html \ $$PWD/data/keyboardModifierMapping.html \ + $$PWD/data/keyboardEvents.html \ $$PWD/data/titleupdate.js \ $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ $$PWD/data/tst_download.qml \ @@ -70,6 +71,7 @@ OTHER_FILES += \ $$PWD/data/tst_webchannel.qml \ $$PWD/data/tst_settings.qml \ $$PWD/data/tst_keyboardModifierMapping.qml \ + $$PWD/data/tst_keyboardEvents.qml \ $$PWD/data/icons/favicon.png \ $$PWD/data/icons/gray128.png \ $$PWD/data/icons/gray16.png \ diff --git a/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html b/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html new file mode 100644 index 0000000000000000000000000000000000000000..d536d849fe5d9f15b4bb50e44ab5e4c26bc5b727 --- /dev/null +++ b/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html @@ -0,0 +1,98 @@ +<html> +<head> + <style> + div { + width: 300px; + margin-bottom: 10px; + } + + #div_container { + display: inline-block; + } + + #div_container div { + width: 100px; + height: 100px; + border: 2px solid black; + padding: 10px; + margin: 0 10px 0 10px; + float: left; + } + + #div_container div:focus { + border: 2px solid red; + } + + #form_container span { + display: block; + padding-bottom: 10px; + } + + #form_container label { + float: left; + text-align: right; + width: 50px; + margin-right: 20px; + } + </style> +</head> + +<body onload="document.getElementById('first_div').focus()"> + <div id="div_container"> + <div id="first_div" tabindex="0">First</div> + <div id="second_div" tabindex="0">Second</div> + </div> + + <div id="form_container"> + <form><fieldset> + <legend>Form</legend> + + <span> + <label for="text_input">text</label> + <input id="text_input" type="text" /> + </span> + + <span> + <input id="radio1" type="radio" name="radio">radio1</input> + <input id="radio2" type="radio" name="radio">radio2</input> + </span> + + <span> + <input id="checkbox1" type="checkbox" name="checkbox1" checked="true">checkbox1</input> + <input id="checkbox2" type="checkbox" name="checkbox2" checked="true">checkbox2</input> + </span> + + <span> + <label for="number_input">number</label> + <input id="number_input" type="number" min="0" max="10" value="5" /> + </span> + + <span> + <label for="range_input">range</label> + <input id="range_input" type="range" min="0" max="10" value="5" /> + </span> + + <span> + <label for="search_input">search</label> + <input id="search_input" type="search" value="test" /> + </span> + + <input id="submit_button" type="submit" value="Submit" /> + </fieldset></form> + </div> + + <div> + <select id="combobox"> + <option value="a">a</option> + <option value="b">b</option> + <option value="c">c</option> + </select> + </div> + + <div> + <a id="first_hyperlink" href="">First</a> + <br /> + <a id="second_hyperlink" href="">Second</a> + </div> +</body> +</html> diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 156c56933608b2f4cd11b81903a941c34dd1c67c..9966ad9ee65ae4d5d50ea1b7001cd08a886791de 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -82,6 +82,7 @@ private Q_SLOTS: void changeLocale(); void inputMethodsTextFormat_data(); void inputMethodsTextFormat(); + void keyboardEvents(); }; // This will be called before the first test function is executed. @@ -924,5 +925,94 @@ void tst_QWebEngineView::inputMethodsTextFormat() QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), string); } +void tst_QWebEngineView::keyboardEvents() +{ + QWebEngineView view; + view.show(); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.load(QUrl("qrc:///resources/keyboardEvents.html")); + QVERIFY(loadFinishedSpy.wait()); + + QStringList elements; + elements << "first_div" << "second_div"; + elements << "text_input" << "radio1" << "checkbox1" << "checkbox2"; + elements << "number_input" << "range_input" << "search_input"; + elements << "submit_button" << "combobox" << "first_hyperlink" << "second_hyperlink"; + + // Iterate over the elements of the test page with the Tab key. This tests whether any + // element blocks the in-page navigation by Tab. + for (const QString &elementId : elements) { + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), elementId); + QTest::keyPress(view.focusProxy(), Qt::Key_Tab); + } + + // Move back to the radio buttons with the Shift+Tab key combination + for (int i = 0; i < 10; ++i) + QTest::keyPress(view.focusProxy(), Qt::Key_Tab, Qt::ShiftModifier); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("radio2")); + + // Test the Space key by checking a radio button + QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool()); + QTest::keyClick(view.focusProxy(), Qt::Key_Space); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool()); + + // Test the Left key by switching the radio button + QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio1').checked").toBool()); + QTest::keyPress(view.focusProxy(), Qt::Key_Left); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("radio1")); + QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool()); + QVERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('radio1').checked").toBool()); + + // Test the Space key by unchecking a checkbox + evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').focus()"); + QVERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').checked").toBool()); + QTest::keyClick(view.focusProxy(), Qt::Key_Space); + QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').checked").toBool()); + + // Test the Up and Down keys by changing the value of a spinbox + evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').focus()"); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 5); + QTest::keyPress(view.focusProxy(), Qt::Key_Up); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 6); + QTest::keyPress(view.focusProxy(), Qt::Key_Down); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 5); + + // Test the Left, Right, Home, PageUp, End and PageDown keys by changing the value of a slider + evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').focus()"); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("5")); + QTest::keyPress(view.focusProxy(), Qt::Key_Left); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("4")); + QTest::keyPress(view.focusProxy(), Qt::Key_Right); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("5")); + QTest::keyPress(view.focusProxy(), Qt::Key_Home); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("0")); + QTest::keyPress(view.focusProxy(), Qt::Key_PageUp); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("1")); + QTest::keyPress(view.focusProxy(), Qt::Key_End); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("10")); + QTest::keyPress(view.focusProxy(), Qt::Key_PageDown); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("9")); + + // Test the Escape key by removing the content of a search field + evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').focus()"); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').value").toString(), QStringLiteral("test")); + QTest::keyPress(view.focusProxy(), Qt::Key_Escape); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').value").toString().isEmpty()); + + // Test the alpha keys by changing the values in a combobox + evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').focus()"); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("a")); + QTest::keyPress(view.focusProxy(), Qt::Key_B); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("b")); + // Must wait with the second key press to simulate selection of another element + QTest::keyPress(view.focusProxy(), Qt::Key_C, Qt::NoModifier, 1000); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("c")); + + // Test the Enter key by loading a page with a hyperlink + evaluateJavaScriptSync(view.page(), "document.getElementById('first_hyperlink').focus()"); + QTest::keyPress(view.focusProxy(), Qt::Key_Enter); + QVERIFY(loadFinishedSpy.wait()); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc index b32b533c21ae1e2a0d14c82516f1210f42d30786..4809bbebfff4dcd83fa6f9e18b220864793db1a4 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc @@ -5,5 +5,6 @@ <file>resources/input_types.html</file> <file>resources/scrolltest_page.html</file> <file>resources/basic_printing_page.html</file> + <file>resources/keyboardEvents.html</file> </qresource> </RCC>