diff options
Diffstat (limited to 'tests/auto/quick/qmltests')
99 files changed, 3950 insertions, 1468 deletions
diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST index 46bc65923..fc8f9f0d8 100644 --- a/tests/auto/quick/qmltests/BLACKLIST +++ b/tests/auto/quick/qmltests/BLACKLIST @@ -1,2 +1,12 @@ -[WebEngineViewSource::test_viewSourceURL] +[NewWindowRequest::test_loadNewWindowRequest] +macos + +[WebEngineViewContextMenu::test_contextMenuLinkAndSelectedText] +macos + +[CertificateError::test_fatalError] * + +[CertificateError::test_error] +* + diff --git a/tests/auto/quick/qmltests/CMakeLists.txt b/tests/auto/quick/qmltests/CMakeLists.txt new file mode 100644 index 000000000..daae6d60d --- /dev/null +++ b/tests/auto/quick/qmltests/CMakeLists.txt @@ -0,0 +1,94 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +include(../../httpserver/httpserver.cmake) +include(../../util/util.cmake) + +qt_internal_add_test(tst_qmltests + SOURCES + tst_qmltests.cpp + LIBRARIES + Qt::GuiPrivate + Qt::QuickTest + Qt::TestPrivate + Qt::WebEngineQuick + Test::HttpServer + Test::Util +) + +set(testList + tst_action.qml + tst_activeFocusOnPress.qml + tst_audioMuted.qml + tst_contextMenu.qml + tst_basicProfiles.qml + tst_datalist.qml + tst_desktopBehaviorLoadHtml.qml + tst_download.qml + tst_dragHandlerUnderView.qml + tst_favicon.qml + tst_faviconDatabase.qml + tst_filePicker.qml + tst_filesystem.qml + tst_findText.qml + tst_focusOnNavigation.qml + tst_fullScreenRequest.qml + tst_getUserMedia.qml + tst_inputMethod.qml + tst_inputTextDirection.qml + tst_javaScriptDialogs.qml + tst_keyboardEvents.qml + tst_keyboardModifierMapping.qml + tst_linkHovered.qml + tst_loadFail.qml + tst_loadHtml.qml + tst_loadProgress.qml + tst_loadRecursionCrash.qml + tst_loadUrl.qml + tst_mouseClick.qml + tst_mouseMove.qml + tst_navigationHistory.qml + tst_navigationRequested.qml + tst_newViewRequest.qml + tst_notification.qml + tst_properties.qml + tst_runJavaScript.qml + tst_scrollPosition.qml + tst_settings.qml + tst_titleChanged.qml + tst_unhandledKeyEventPropagation.qml + tst_userScripts.qml + tst_userScriptCollection.qml + tst_viewSource.qml + tst_save.qml +) + +if(QT_FEATURE_webengine_webchannel) + list(APPEND testList tst_webchannel.qml) +endif() + +if(QT_FEATURE_ssl) + list(APPEND testList tst_certificateError.qml) +endif() + +if (NOT APPLE) + list(APPEND testList tst_geopermission.qml) +endif() + +set(content "") +foreach(test ${testList}) + set(contents "${contents}${CMAKE_CURRENT_LIST_DIR}/data/${test}\n") +endforeach() +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/webengine.qmltests ${contents}) + +set(tst_qmltests_resource_files + "resources/server.pem" + "resources/server.key" +) + +qt_internal_add_resource(tst_qmltests "tst_qmltests" + PREFIX + "/" + FILES + ${tst_qmltests_resource_files} +) diff --git a/tests/auto/quick/qmltests/data/TestWebEngineView.qml b/tests/auto/quick/qmltests/data/TestWebEngineView.qml index 6db076ae8..415985471 100644 --- a/tests/auto/quick/qmltests/data/TestWebEngineView.qml +++ b/tests/auto/quick/qmltests/data/TestWebEngineView.qml @@ -1,53 +1,38 @@ -/**************************************************************************** -** -** 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.1 -import QtWebEngine 1.7 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine WebEngineView { property var loadStatus: null property bool windowCloseRequestedSignalEmitted: false settings.focusOnNavigationEnabled: true + function loadSucceeded() { return loadStatus == WebEngineView.LoadSucceededStatus } + function loadFailed() { return loadStatus == WebEngineView.LoadFailedStatus } + function loadStopped() { return loadStatus == WebEngineView.LoadStoppedStatus } + + function waitForLoadResult(timeout) { + loadStatus = null + var r = _waitFor(function() { return loadStatus != null && loadStatus != WebEngineView.LoadStartedStatus }, timeout) + return r + } + function waitForLoadSucceeded(timeout) { - var success = _waitFor(function() { return loadStatus == WebEngineView.LoadSucceededStatus }, timeout) loadStatus = null + var success = _waitFor(function() { return loadStatus == WebEngineView.LoadSucceededStatus }, timeout) return success } function waitForLoadFailed(timeout) { - var failure = _waitFor(function() { return loadStatus == WebEngineView.LoadFailedStatus }, timeout) loadStatus = null + var failure = _waitFor(function() { return loadStatus == WebEngineView.LoadFailedStatus }, timeout) return failure } function waitForLoadStopped(timeout) { - var stop = _waitFor(function() { return loadStatus == WebEngineView.LoadStoppedStatus }, timeout) loadStatus = null + var stop = _waitFor(function() { return loadStatus == WebEngineView.LoadStoppedStatus }, timeout) return stop } function waitForWindowCloseRequested() { @@ -55,7 +40,7 @@ WebEngineView { } function _waitFor(predicate, timeout) { if (timeout === undefined) - timeout = 12000; + timeout = 30000; var i = 0 while (i < timeout && !predicate()) { testResult.wait(50) @@ -85,12 +70,14 @@ WebEngineView { function getElementCenter(element) { var center; - runJavaScript("(function() {" + + testCase.tryVerify(function() { + runJavaScript("(function() {" + " var elem = document.getElementById('" + element + "');" + " var rect = elem.getBoundingClientRect();" + " return { 'x': (rect.left + rect.right) / 2, 'y': (rect.top + rect.bottom) / 2 };" + "})();", function(result) { center = result } ); - testCase.tryVerify(function() { return center !== undefined; }); + return center !== undefined; + }); return center; } @@ -101,11 +88,25 @@ WebEngineView { return textSelection; } + function getElementValue(element) { + var elementValue; + runJavaScript("document.getElementById('" + element + "').value", function(result) { + elementValue = result; + }); + testCase.tryVerify(function() { return elementValue != undefined; }); + return elementValue; + } + + function compareElementValue(element, expected) { + testCase.tryVerify(function() { return expected == getElementValue(element); }, 5000, + "Value of element \"" + element + "\" is \"" + expected + "\""); + } + + TestResult { id: testResult } - TestCase { id: testCase } - onLoadingChanged: { - loadStatus = loadRequest.status + onLoadingChanged: function(load) { + loadStatus = load.status } onWindowCloseRequested: { @@ -118,5 +119,38 @@ WebEngineView { testCase.tryVerify(function() { return text !== undefined }) return text } + + function getItemPixel(item) { + var grabImage = Qt.createQmlObject(" + import QtQuick\n + Image { }", testCase) + var itemCanvas = Qt.createQmlObject(" + import QtQuick\n + Canvas { }", testCase) + + // Mark QML images with objectName: "image" to be able to check if the image is loaded. + if (item.objectName === "image") { + testCase.tryVerify(function() { return item.status === Image.Ready }); + } + + item.grabToImage(function(result) { + grabImage.source = result.url + }); + testCase.tryVerify(function() { return grabImage.status === Image.Ready }); + + itemCanvas.width = item.width; + itemCanvas.height = item.height; + var ctx = itemCanvas.getContext("2d"); + ctx.drawImage(grabImage, 0, 0, grabImage.width, grabImage.height); + var imageData = ctx.getImageData(Math.round(itemCanvas.width/2), + Math.round(itemCanvas.height/2), + itemCanvas.width, + itemCanvas.height); + + grabImage.destroy(); + itemCanvas.destroy(); + + return imageData.data; + } } diff --git a/tests/auto/quick/qmltests/data/accepttypes.html b/tests/auto/quick/qmltests/data/accepttypes.html new file mode 100644 index 000000000..aff39f96e --- /dev/null +++ b/tests/auto/quick/qmltests/data/accepttypes.html @@ -0,0 +1,21 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title>Default title</title> +</head> + +<body> +<input type="file" name="file" id="upfile" accept=""> + +<script> +window.onload = function() { + document.getElementById("upfile").focus(); +} + +function setAcceptType(acceptType) { + document.getElementById("upfile").accept = acceptType; + document.title = acceptType; +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/alert.html b/tests/auto/quick/qmltests/data/alert.html new file mode 100644 index 000000000..89715a727 --- /dev/null +++ b/tests/auto/quick/qmltests/data/alert.html @@ -0,0 +1,5 @@ +<html> +<head> + <script> alert("Hello Qt"); </script> +</head> +</html> diff --git a/tests/auto/quick/qmltests/data/confirm.html b/tests/auto/quick/qmltests/data/confirm.html new file mode 100644 index 000000000..a4fc5b532 --- /dev/null +++ b/tests/auto/quick/qmltests/data/confirm.html @@ -0,0 +1,10 @@ +<html> +<head> + <script> + if (confirm("Confirm test")) + document.title += " ACCEPTED"; + else + document.title += " REJECTED"; + </script> +</head> +</html> diff --git a/tests/auto/quick/qmltests/data/confirmclose.html b/tests/auto/quick/qmltests/data/confirmclose.html new file mode 100644 index 000000000..c2acbb67f --- /dev/null +++ b/tests/auto/quick/qmltests/data/confirmclose.html @@ -0,0 +1,6 @@ +<html> +<body onbeforeunload="return 'You are about to miss out on some awesome content.';" + onmousedown="window.mousePressReceived = true;"> + Be greeted, precious viewer! +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/directoryupload.html b/tests/auto/quick/qmltests/data/directoryupload.html new file mode 100644 index 000000000..adc408ebb --- /dev/null +++ b/tests/auto/quick/qmltests/data/directoryupload.html @@ -0,0 +1,17 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title> Directory Upload </title> +<script src = "./titleupdate.js"> +</script> +</head> + +<body> +<input type="file" id="upfile" webkitdirectory="" directory="" onchange="updateTitle()"> +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-candidates-gray.html b/tests/auto/quick/qmltests/data/favicon-candidates-gray.html new file mode 100644 index 000000000..ebea35b02 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-candidates-gray.html @@ -0,0 +1,29 @@ +<html> + <head> + <title>Gray Candidate Favicons Test</title> + <link rel="shortcut icon" href="icons/gray16.png" /> + <link rel="shortcut icon" href="icons/gray32.png" /> + <link rel="shortcut icon" href="icons/gray64.png" /> + <link rel="shortcut icon" href="icons/gray128.png" /> + <link rel="shortcut icon" href="icons/gray255.png" /> + </head> + <body> + <h1>Gray Candidate Favicons Test</h1> + <table style="width:100%"> + <tr> + <td align="center"><img src="icons/gray16.png" height="16" width="16" border="1" /></td> + <td align="center"><img src="icons/gray32.png" height="32" width="32" border="1" /></td> + <td align="center"><img src="icons/gray64.png" height="64" width="64" border="1" /></td> + <td align="center"><img src="icons/gray128.png" height="128" width="128" border="1" /></td> + <td align="center"><img src="icons/gray255.png" height="255" width="255" border="1" /></td> + </tr> + <tr> + <td align="center">16x16</td> + <td align="center">32x32</td> + <td align="center">64x64</td> + <td align="center">128x128</td> + <td align="center">255x255</td> + </tr> + </table> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-misc.html b/tests/auto/quick/qmltests/data/favicon-misc.html new file mode 100644 index 000000000..03d1086ff --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-misc.html @@ -0,0 +1,11 @@ +<html> + <head> + <title>Favicon Test</title> + <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> + <h1>Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-multi-gray.html b/tests/auto/quick/qmltests/data/favicon-multi-gray.html new file mode 100644 index 000000000..24b71640f --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-multi-gray.html @@ -0,0 +1,25 @@ +<html> + <head> + <title>Gray Multi-sized Favicon Test</title> + <link rel="shortcut icon" href="icons/grayicons.ico" /> + </head> + <body> + <h1>Gray Multi-sized Favicon Test</h1> + <table style="width:100%"> + <tr> + <td align="center"><img src="icons/gray16.png" height="16" width="16" border="1" /></td> + <td align="center"><img src="icons/gray32.png" height="32" width="32" border="1" /></td> + <td align="center"><img src="icons/gray64.png" height="64" width="64" border="1" /></td> + <td align="center"><img src="icons/gray128.png" height="128" width="128" border="1" /></td> + <td align="center"><img src="icons/gray255.png" height="255" width="255" border="1" /></td> + </tr> + <tr> + <td align="center">16x16</td> + <td align="center">32x32</td> + <td align="center">64x64</td> + <td align="center">128x128</td> + <td align="center">255x255</td> + </tr> + </table> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-multi.html b/tests/auto/quick/qmltests/data/favicon-multi.html new file mode 100644 index 000000000..cc5f3fd66 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-multi.html @@ -0,0 +1,9 @@ +<html> + <head> + <title>Multi-sized Favicon Test</title> + <link rel="shortcut icon" sizes="16x16 32x23 64x64" href="icons/qtmulti.ico" /> + </head> + <body> + <h1>Multi-sized Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-shortcut.html b/tests/auto/quick/qmltests/data/favicon-shortcut.html new file mode 100644 index 000000000..786cdb816 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-shortcut.html @@ -0,0 +1,10 @@ +<html> + <head> + <title>Favicon Test</title> + <link rel="shortcut icon" href="icons/qt32.ico" /> + <link rel="shortcut icon" href="icons/qt144.png" /> + </head> + <body> + <h1>Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-single.html b/tests/auto/quick/qmltests/data/favicon-single.html new file mode 100644 index 000000000..eb4675c75 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-single.html @@ -0,0 +1,9 @@ +<html> + <head> + <title>Favicon Test</title> + <link rel="shortcut icon" href="icons/qt32.ico" /> + </head> + <body> + <h1>Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-touch.html b/tests/auto/quick/qmltests/data/favicon-touch.html new file mode 100644 index 000000000..271783434 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-touch.html @@ -0,0 +1,10 @@ +<html> + <head> + <title>Favicon Test</title> + <link rel="apple-touch-icon" href="icons/qt32.ico" /> + <link rel="apple-touch-icon" href="icons/qt144.png" /> + </head> + <body> + <h1>Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-unavailable.html b/tests/auto/quick/qmltests/data/favicon-unavailable.html new file mode 100644 index 000000000..c45664294 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-unavailable.html @@ -0,0 +1,9 @@ +<html> + <head> + <title>Favicon Test</title> + <link rel="shortcut icon" href="icons/unavailable.ico" /> + </head> + <body> + <h1>Favicon Test</h1> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon2.html b/tests/auto/quick/qmltests/data/favicon2.html new file mode 100644 index 000000000..81c2690fe --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon2.html @@ -0,0 +1,10 @@ +<html> +<head> +</head> +<link type="image/png" href="icons/small-favicon.png" sizes="16x16" rel="icon" /> +<body> +<p>It's expected that you see a favicon displayed for this page when you open it as a local file.</p> +<p>The favicon looks like this:</p> +<img src="icons/small-favicon.png"/> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/filesystemapi.html b/tests/auto/quick/qmltests/data/filesystemapi.html new file mode 100644 index 000000000..ab1a33e4d --- /dev/null +++ b/tests/auto/quick/qmltests/data/filesystemapi.html @@ -0,0 +1,66 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title> Failed to Upload </title> +</script> +</head> + +<body> +<button>Request File Picker</button> +<script> + async function handleDirectoryEntry( dirHandle, out ) { + for await (const entry of dirHandle.values()) { + if (entry.kind === "file"){ + const file = await entry.getFile(); + out[ file.name ] = file; + } + if (entry.kind === "directory") { + const newHandle = await dirHandle.getDirectoryHandle( entry.name, { create: false } ); + const newOut = out[ entry.name ] = {}; + await handleDirectoryEntry( newHandle, newOut ); + } + } + } + const button = document.querySelector('button'); + button.addEventListener('click', async function() { + switch(window.dialogType) { + case "savePicker": + const saveFileHandle = await window.showSaveFilePicker(); + const writable = await saveFileHandle.createWritable(); + await writable.write(new Blob(['TEST_CONTENT'])); + await writable.close(); + console.log("TEST:DONE") + break; + case "filePicker": + let [openFileHandle] = await window.showOpenFilePicker(); + const options = {}; + options.mode = 'readwrite' + await openFileHandle.requestPermission(options) + const file = await openFileHandle.getFile(); + const contents = await file.text(); + console.log("TEST:" + contents) + console.log("TEST:DONE") + break; + case "directoryPicker": + console.log("start") + const dirHandle = await window.showDirectoryPicker(); + for await (const entry of dirHandle.values()) { + if (entry.kind === "file"){ + continue + } + if (entry.kind === "directory") { + console.log("TEST:" + entry.name) + } + } + console.log("TEST:DONE") + break; + default: + } + }); + window.onload = function() { + window.dialogType = window.location.href.split('=')[1]; + document.querySelector('button').focus() + } +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/geolocation.html b/tests/auto/quick/qmltests/data/geolocation.html index 8b116c8ee..e8c54bc58 100644 --- a/tests/auto/quick/qmltests/data/geolocation.html +++ b/tests/auto/quick/qmltests/data/geolocation.html @@ -3,16 +3,21 @@ <title>Geolocation Permission API Test</title> <script> +var errorMessage; +var handled = false; + function successHandler(location) { var message = document.getElementById("message"); message.innerHTML = "Latitude: " + location.coords.latitude + "<br>Longitude: " + location.coords.longitude; - console.error("Success"); + errorMessage = ""; + handled = true; } function errorHandler(error) { - console.error(error.message); + errorMessage = error.message; + handled = true; } <!-- One shot example --> diff --git a/tests/auto/quick/qmltests/data/icons/gray128.png b/tests/auto/quick/qmltests/data/icons/gray128.png Binary files differnew file mode 100644 index 000000000..bf1cfaba0 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray128.png diff --git a/tests/auto/quick/qmltests/data/icons/gray16.png b/tests/auto/quick/qmltests/data/icons/gray16.png Binary files differnew file mode 100644 index 000000000..2a1a91a76 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray16.png diff --git a/tests/auto/quick/qmltests/data/icons/gray255.png b/tests/auto/quick/qmltests/data/icons/gray255.png Binary files differnew file mode 100644 index 000000000..549169551 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray255.png diff --git a/tests/auto/quick/qmltests/data/icons/gray32.png b/tests/auto/quick/qmltests/data/icons/gray32.png Binary files differnew file mode 100644 index 000000000..b269a528f --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray32.png diff --git a/tests/auto/quick/qmltests/data/icons/gray64.png b/tests/auto/quick/qmltests/data/icons/gray64.png Binary files differnew file mode 100644 index 000000000..e02559e5b --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray64.png diff --git a/tests/auto/quick/qmltests/data/icons/grayicons.ico b/tests/auto/quick/qmltests/data/icons/grayicons.ico Binary files differnew file mode 100644 index 000000000..8d8fee839 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/grayicons.ico diff --git a/tests/auto/quick/qmltests/data/icons/qt144.png b/tests/auto/quick/qmltests/data/icons/qt144.png Binary files differnew file mode 100644 index 000000000..050b1e066 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/qt144.png diff --git a/tests/auto/quick/qmltests/data/icons/qt32.ico b/tests/auto/quick/qmltests/data/icons/qt32.ico Binary files differnew file mode 100644 index 000000000..2f6fcb5bc --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/qt32.ico diff --git a/tests/auto/quick/qmltests/data/icons/qtmulti.ico b/tests/auto/quick/qmltests/data/icons/qtmulti.ico Binary files differnew file mode 100644 index 000000000..81e5a22e8 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/qtmulti.ico diff --git a/tests/auto/quick/qmltests/data/icons/small-favicon.png b/tests/auto/quick/qmltests/data/icons/small-favicon.png Binary files differnew file mode 100644 index 000000000..8cf9a50a4 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/small-favicon.png diff --git a/tests/auto/quick/qmltests/data/multifileupload.html b/tests/auto/quick/qmltests/data/multifileupload.html new file mode 100644 index 000000000..d41ea15c0 --- /dev/null +++ b/tests/auto/quick/qmltests/data/multifileupload.html @@ -0,0 +1,18 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title> Failed to Upload </title> +<script src = "./titleupdate.js"> +</script> +</head> + +<body> +<input type="file" name="file" id="upfile" onchange="updateTitle()" multiple/> + +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/prompt.html b/tests/auto/quick/qmltests/data/prompt.html new file mode 100644 index 000000000..3293c0dcf --- /dev/null +++ b/tests/auto/quick/qmltests/data/prompt.html @@ -0,0 +1,7 @@ +<html> +<head> + <script> + document.title = prompt("Please, reverse the default value", "Hello Qt"); + </script> +</head> +</html> diff --git a/tests/auto/quick/qmltests/data/singlefileupload.html b/tests/auto/quick/qmltests/data/singlefileupload.html new file mode 100644 index 000000000..ac91c2c0d --- /dev/null +++ b/tests/auto/quick/qmltests/data/singlefileupload.html @@ -0,0 +1,18 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title> Failed to Upload </title> +<script src = "./titleupdate.js"> +</script> +</head> + +<body> +<input type="file" name="file" id="upfile" onchange="updateTitle()"/> + +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/test2.html b/tests/auto/quick/qmltests/data/test2.html index 629c2a063..06b1c40cb 100644 --- a/tests/auto/quick/qmltests/data/test2.html +++ b/tests/auto/quick/qmltests/data/test2.html @@ -1,6 +1,6 @@ <html> <head><title>Test page with huge link area</title></head> <body> -<a title="A title" href="test1.html"><img width=200 height=200></a> +<a id="link" title="A title" href="test1.html"><div style="width:200px; height:200px; background-color:red"></div></a> </body> </html> diff --git a/tests/auto/quick/qmltests/data/test4.html b/tests/auto/quick/qmltests/data/test4.html index c9b395ee5..82830668a 100644 --- a/tests/auto/quick/qmltests/data/test4.html +++ b/tests/auto/quick/qmltests/data/test4.html @@ -9,7 +9,6 @@ font-size: 50px; } </style> - <meta name="viewport" content="initial-scale=2.0"/> </head> <body> <button onclick="scrollWin()" id="scroll">Click me to scroll!</button><br><br> @@ -24,6 +23,7 @@ } </script> <div id="content"> + <p><a id='anchor' href='#anchor'>anchor</a> <p>bla00 <p>bla01 <p>bla02 diff --git a/tests/auto/quick/qmltests/data/titleupdate.js b/tests/auto/quick/qmltests/data/titleupdate.js new file mode 100644 index 000000000..720e83676 --- /dev/null +++ b/tests/auto/quick/qmltests/data/titleupdate.js @@ -0,0 +1,17 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +function updateTitle() +{ + var inp = document.getElementById("upfile"); + var allfiles = new String(""); + var name = new String(""); + for (var i = 0; i < inp.files.length; ++i) { + name = inp.files.item(i).name; + if (allfiles.length == 0) + allfiles = name; + else + allfiles = allfiles + "," + name; + } + document.title = allfiles; +} diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml index 852d4145a..9e49c2dbf 100644 --- a/tests/auto/quick/qmltests/data/tst_action.qml +++ b/tests/auto/quick/qmltests/data/tst_action.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtTest 1.0 -import QtWebEngine 1.8 +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -41,7 +16,7 @@ TestWebEngineView { } TestCase { - id: actionTests + id: testCase name: "WebEngineAction" when: windowShown @@ -90,7 +65,9 @@ TestWebEngineView { { webAction: WebEngineView.Indent, text: "&Indent", iconName: "", enabled: true }, { webAction: WebEngineView.Outdent, text: "&Outdent", iconName: "", enabled: true }, { webAction: WebEngineView.InsertOrderedList, text: "Insert &Ordered List", iconName: "", enabled: true }, - { webAction: WebEngineView.InsertUnorderedList, text: "Insert &Unordered List", iconName: "", enabled: true } + { webAction: WebEngineView.InsertUnorderedList, text: "Insert &Unordered List", iconName: "", enabled: true }, + { webAction: WebEngineView.ChangeTextDirectionLTR, text: "Change text direction left to right", iconName: "", enabled: true }, + { webAction: WebEngineView.ChangeTextDirectionRTL, text: "Change text direction right to left", iconName: "", enabled: true } ]; } @@ -116,8 +93,8 @@ TestWebEngineView { var stopAction = webEngineView.action(WebEngineView.Stop); verify(stopAction); - var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: selectAction, signalName: "triggered"}); - var stopTriggerSpy = createTemporaryObject(signalSpy, actionTests, {target: stopAction, signalName: "triggered"}); + var triggerSpy = createTemporaryObject(signalSpy, testCase, {target: selectAction, signalName: "triggered"}); + var stopTriggerSpy = createTemporaryObject(signalSpy, testCase, {target: stopAction, signalName: "triggered"}); verify(selectAction.enabled); selectAction.trigger(); @@ -148,7 +125,7 @@ TestWebEngineView { compare(enabledSpy.count, 0); selectAllAction.trigger(); compare(triggerSpy.count, 0); - compare(getTextSelection(), ""); + compare(webEngineView.getTextSelection(), ""); // Focus content by focusing window from JavaScript. Edit actions should be enabled and functional. webView.runJavaScript("window.focus();"); @@ -157,6 +134,7 @@ TestWebEngineView { selectAllAction.trigger(); compare(triggerSpy.count, 1); tryVerify(function() { return webView.getTextSelection() === "foo bar" }); + webView.destroy(); } function test_editActionsWithInitialFocus() { @@ -180,6 +158,7 @@ TestWebEngineView { selectAllAction.trigger(); compare(triggerSpy.count, 1); tryVerify(function() { return webView.getTextSelection() === "foo bar" }); + webView.destroy(); } } } diff --git a/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml b/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml index c360a1da2..77968f6b6 100644 --- a/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml +++ b/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml @@ -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 -import QtQuick 2.5 -import QtTest 1.0 +import QtQuick +import QtTest Item { id: root @@ -55,6 +30,7 @@ Item { } TestCase { + id: testCase name: "ActiveFocusOnPress" when:windowShown diff --git a/tests/auto/quick/qmltests/data/tst_audioMuted.qml b/tests/auto/quick/qmltests/data/tst_audioMuted.qml index c626d07a0..85f813f0c 100644 --- a/tests/auto/quick/qmltests/data/tst_audioMuted.qml +++ b/tests/auto/quick/qmltests/data/tst_audioMuted.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.4 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: view @@ -42,7 +17,7 @@ TestWebEngineView { } TestCase { - id: test + id: testCase name: "WebEngineViewAudioMuted" function test_audioMuted() { diff --git a/tests/auto/quick/qmltests/data/tst_basicProfiles.qml b/tests/auto/quick/qmltests/data/tst_basicProfiles.qml new file mode 100644 index 000000000..97a25cdd8 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_basicProfiles.qml @@ -0,0 +1,90 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Qt.labs.platform + +Item { + WebEngineProfile { id: otrProfile; /* MEMO implicit offTheRecord: true */ } + WebEngineProfile { id: nonOtrProfile; offTheRecord: false } + + function getPath(path, offset = 1) { return path.substr(path.indexOf(':') + offset, path.length) } + property string appDataLocation: getPath(getPath(StandardPaths.writableLocation(StandardPaths.AppDataLocation).toString(), 3)) + property string cacheLocation: getPath(getPath(StandardPaths.writableLocation(StandardPaths.CacheLocation).toString(), 3)) + property string downloadLocation: getPath(getPath(StandardPaths.writableLocation(StandardPaths.DownloadLocation).toString(), 3)) + + TestCase { + name: "BasicProfiles" + + function test_defaultProfile() { + let p = WebEngine.defaultProfile + verify(p.offTheRecord) + + compare(p.storageName, '') + compare(p.cachePath, '') + compare(getPath(p.persistentStoragePath), appDataLocation + '/QtWebEngine/OffTheRecord') + compare(p.httpCacheType, WebEngineProfile.MemoryHttpCache) + compare(p.httpCacheMaximumSize, 0) + compare(p.persistentCookiesPolicy, WebEngineProfile.NoPersistentCookies) + + compare(getPath(p.downloadPath), downloadLocation) + compare(p.httpAcceptLanguage, '') + verify(p.httpUserAgent !== '') + compare(p.spellCheckEnabled, false) + compare(p.spellCheckLanguages, []) + + compare(p.userScripts.collection, []) + } + + function test_otrProfile() { + let p = otrProfile + verify(p.offTheRecord) + + compare(p.storageName, '') + compare(p.cachePath, '') + compare(getPath(p.persistentStoragePath), appDataLocation + '/QtWebEngine/OffTheRecord') + compare(p.httpCacheType, WebEngineProfile.MemoryHttpCache) + compare(p.httpCacheMaximumSize, 0) + compare(p.persistentCookiesPolicy, WebEngineProfile.NoPersistentCookies) + + compare(getPath(p.downloadPath), downloadLocation) + compare(p.httpAcceptLanguage, '') + verify(p.httpUserAgent !== '') + compare(p.spellCheckEnabled, false) + compare(p.spellCheckLanguages, []) + + compare(p.userScripts.collection, []) + } + + function test_nonOtrProfile() { + let p = nonOtrProfile + verify(!p.offTheRecord) + + compare(p.storageName, '') + compare(p.cachePath, '') + compare(getPath(p.persistentStoragePath), appDataLocation + '/QtWebEngine/UnknownProfile') + compare(p.httpCacheType, WebEngineProfile.MemoryHttpCache) + compare(p.httpCacheMaximumSize, 0) + compare(p.persistentCookiesPolicy, WebEngineProfile.NoPersistentCookies) + + compare(getPath(p.downloadPath), downloadLocation) + compare(p.httpAcceptLanguage, '') + verify(p.httpUserAgent !== '') + compare(p.spellCheckEnabled, false) + compare(p.spellCheckLanguages, []) + + compare(p.userScripts.collection, []) + + p.storageName = 'Test' + compare(p.storageName, 'Test') + compare(getPath(p.cachePath), cacheLocation + '/QtWebEngine/' + p.storageName) + compare(getPath(p.persistentStoragePath), appDataLocation + '/QtWebEngine/' + p.storageName) + + compare(p.httpCacheType, WebEngineProfile.DiskHttpCache) + compare(p.httpCacheMaximumSize, 0) + compare(p.persistentCookiesPolicy, WebEngineProfile.AllowPersistentCookies) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_certificateError.qml b/tests/auto/quick/qmltests/data/tst_certificateError.qml new file mode 100644 index 000000000..220ef9ac8 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_certificateError.qml @@ -0,0 +1,122 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +import Test.Shared as Shared + +TestWebEngineView { + id: view; width: 320; height: 320 + + property bool deferError: false + property bool acceptCertificate: false + + SignalSpy { + id: spyError + target: view + signalName: 'certificateError' + } + + TestCase { + id: testCase + name: 'CertificateError' + when: windowShown + + function initTestCase() { + Shared.HttpsServer.setExpectError(true) + Shared.HttpsServer.newRequest.connect(function (request) { + request.setResponseBody('<html><body>Test</body></html>') + request.sendResponse() + }) + view.settings.errorPageEnabled = false + } + + function init() { + verify(Shared.HttpsServer.start()) + } + + function cleanup() { + Shared.HttpsServer.stop() + view.deferError = false + view.acceptCertificate = false + spyError.clear() + } + + function test_error_data() { + return [ + { tag: 'reject', deferError: false, acceptCertificate: false, expectedContent: '' }, + { tag: 'defer_reject', deferError: true, acceptCertificate: false, expectedContent: '' }, + { tag: 'defer_accept', deferError: true, acceptCertificate: true, expectedContent: 'Test' }, + ] + } + + function test_error(data) { + view.deferError = data.deferError + view.acceptCertificate = data.acceptCertificate + var handleCertificateError = function(error) { + if (deferError) + error.defer() + else if (acceptCertificate) + error.acceptCertificate() + else + error.rejectCertificate() + } + view.certificateError.connect(handleCertificateError) + + const server_url = Shared.HttpsServer.url() + view.url = server_url + + if (data.deferError) { + spyError.wait() + compare(spyError.count, 1) + compare('', view.getBodyText()) + + let error = spyError.signalArguments[0][0] + if (data.acceptCertificate) + error.acceptCertificate() + else + error.rejectCertificate() + } + + if (data.acceptCertificate) + verify(view.waitForLoadSucceeded()) + else + verify(view.waitForLoadFailed()) + + compare(spyError.count, 1) + compare(data.expectedContent, view.getBodyText()) + + view.certificateError.disconnect(handleCertificateError) + + let error = spyError.signalArguments[0][0] + compare(error.url, server_url) + verify(error.description.length > 0) + verify(error.overridable) + compare(error.type, WebEngineCertificateError.CertificateAuthorityInvalid) + } + + function test_fatalError() { + let error = undefined + var handleCertificateError = function(e) { error = e; } + view.certificateError.connect(handleCertificateError); + + view.url = Qt.resolvedUrl('https://revoked.badssl.com'); + if (!view.waitForLoadResult()) { + verify(!error, "There shouldn't be any certificate error if not loaded due to missing internet access!"); + skip("Couldn't load page from network, skipping test."); + } + view.certificateError.disconnect(handleCertificateError); + + // revoked certificate might not be reported as invalid by chromium and the load will silently succeed + const failed = view.loadStatus == WebEngineView.LoadFailedStatus, hasError = Boolean(error) + compare(hasError, failed) + if (failed) { + verify(!error.overridable); + // Fatal certificate errors are implicitly rejected. But second call should not cause crash. + error.rejectCertificate(); + } + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_contextMenu.qml b/tests/auto/quick/qmltests/data/tst_contextMenu.qml index 99450a159..58e27b8ba 100644 --- a/tests/auto/quick/qmltests/data/tst_contextMenu.qml +++ b/tests/auto/quick/qmltests/data/tst_contextMenu.qml @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtQuick.Controls 1.4 -import QtTest 1.0 -import QtWebEngine 1.6 +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import "../mock-delegates/TestParams" TestWebEngineView { id: webEngineView @@ -40,7 +15,7 @@ TestWebEngineView { property var mediaType: null property string selectedText: "" - onContextMenuRequested: { + onContextMenuRequested: function (request) { linkText = request.linkText; mediaType = request.mediaType; selectedText = request.selectedText; @@ -52,38 +27,20 @@ TestWebEngineView { signalName: "contextMenuRequested" } - function getContextMenus() { - var data = webEngineView.data; - var contextMenus = []; - - for (var i = 0; i < data.length; i++) { - if (data[i].type == MenuItemType.Menu) { - contextMenus.push(data[i]); - } - } - return contextMenus; - } - - function destroyContextMenu() { - contextMenuTest.keyPress(Qt.Key_Escape); - return getContextMenus().length == 0; - } - TestCase { - id: contextMenuTest + id: testCase name: "WebEngineViewContextMenu" when: windowShown function init() { - var contextMenus = getContextMenus(); - compare(contextMenus.length, 0); + MenuParams.isMenuOpened = false; } function cleanup() { contextMenuRequestedSpy.clear(); } - function test_contextMenu_data() { + function test_contextMenuRequest_data() { return [ { tag: "defaultContextMenu", userHandled: false, accepted: false }, { tag: "defaultContextMenuWithConnect", userHandled: true, accepted: false }, @@ -91,11 +48,7 @@ TestWebEngineView { ]; } - function test_contextMenu(row) { - if (Qt.platform.os == "osx") { - skip("When the menu pops up on macOS, it does not return and the test fails after time out."); - } - + function test_contextMenuRequest(row) { function contextMenuHandler(request) { request.accepted = row.accepted; } @@ -109,22 +62,12 @@ TestWebEngineView { mouseClick(webEngineView, 20, 20, Qt.RightButton); contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); + tryCompare(MenuParams, "isMenuOpened", !row.accepted); - // There should be maximum one ContextMenu present at a time - var contextMenus = getContextMenus(); - verify(contextMenus.length <= 1); - compare(contextMenus[0] != null, !row.accepted); - - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); webEngineView.contextMenuRequested.disconnect(contextMenuHandler); } function test_contextMenuLinkAndSelectedText() { - if (Qt.platform.os == "osx") { - skip("When the menu pops up on macOS, it does not return and the test fails after time out."); - } - webEngineView.loadHtml("<html><body>" + "<span id='text'>Text </span>" + "<a id='link' href='test1.html'>Link</a>" + @@ -137,9 +80,6 @@ TestWebEngineView { contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); - var contextMenus = getContextMenus(); - compare(contextMenus.length, 1); - verify(contextMenus[0]); compare(linkText, "Link"); compare(mediaType, ContextMenuRequest.MediaTypeNone); compare(selectedText, ""); @@ -150,8 +90,6 @@ TestWebEngineView { verify(webEngineView.action(WebEngineView.CopyLinkToClipboard).enabled); contextMenuRequestedSpy.clear(); - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); // 2. Everything is selected, right click on the link webEngineView.triggerWebAction(WebEngineView.SelectAll); @@ -161,16 +99,11 @@ TestWebEngineView { contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); - contextMenus = getContextMenus(); - compare(contextMenus.length, 1); - verify(contextMenus[0]); compare(linkText, "Link"); compare(mediaType, ContextMenuRequest.MediaTypeNone); compare(selectedText, "Text Link"); contextMenuRequestedSpy.clear(); - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); // 3. Everything is selected, right click on the text var textCenter = getElementCenter("text"); @@ -178,22 +111,12 @@ TestWebEngineView { contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); - contextMenus = getContextMenus(); - compare(contextMenus.length, 1); - verify(contextMenus[0]); compare(linkText, ""); compare(mediaType, ContextMenuRequest.MediaTypeNone); compare(selectedText, "Text Link"); - - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); } function test_contextMenuMediaType() { - if (Qt.platform.os == "osx") { - skip("When the menu pops up on macOS, it does not return and the test fails after time out."); - } - webEngineView.url = Qt.resolvedUrl("favicon.html"); verify(webEngineView.waitForLoadSucceeded()); // 1. Right click on the image @@ -202,30 +125,19 @@ TestWebEngineView { contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); - var contextMenus = getContextMenus(); - compare(contextMenus.length, 1); - verify(contextMenus[0]); compare(linkText, ""); compare(mediaType, ContextMenuRequest.MediaTypeImage); compare(selectedText, ""); contextMenuRequestedSpy.clear(); - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); // 2. Right click out of the image mouseClick(webEngineView, center.x + 30, center.y, Qt.RightButton); contextMenuRequestedSpy.wait(); compare(contextMenuRequestedSpy.count, 1); - contextMenus = getContextMenus(); - compare(contextMenus.length, 1); - verify(contextMenus[0]); compare(linkText, ""); compare(mediaType, ContextMenuRequest.MediaTypeNone); compare(selectedText, ""); - - // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying - tryVerify(destroyContextMenu); } } } diff --git a/tests/auto/quick/qmltests/data/tst_datalist.qml b/tests/auto/quick/qmltests/data/tst_datalist.qml new file mode 100644 index 000000000..f739639b2 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_datalist.qml @@ -0,0 +1,180 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtTest +import QtWebEngine + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + property string 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>" + + function listView() { + if (webEngineView.parent.visibleChildren.length == 1) { + // No popup case. + return null; + } + + let overlay = null; + for (let i = 0; i < webEngineView.parent.visibleChildren.length; ++i) { + let child = webEngineView.parent.visibleChildren[i]; + if (child instanceof Overlay) { + overlay = child; + break; + } + } + + if (!overlay) + return null; + + let popupItem = null; + for (let i = 0; i < overlay.visibleChildren[0].visibleChildren.length; ++i) { + let child = overlay.visibleChildren[0].visibleChildren[i]; + if (child.objectName == "QQuickPopupItem") { + popupItem = child; + } + } + + if (!popupItem) + return null; + + for (let i = 0; i < popupItem.visibleChildren.length; ++i) { + let child = popupItem.visibleChildren[i]; + if (child instanceof ListView) + return child; + } + + return null; + } + + TestCase { + id: testCase + name: "WebEngineDatalist" + when: windowShown + + function test_showAndHide() { + webEngineView.loadHtml(webEngineView.html); + verify(webEngineView.waitForLoadSucceeded()); + + var values = ""; + webEngineView.runJavaScript( + "(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;" + + "})();", function(result) { values = result; }); + tryVerify(function() { return values.length != 0; }); + compare(values, ["Internet Explorer", "Firefox", "Chrome", "Opera", "Safari"]); + compareElementValue("browserInput", ""); + + // Make sure there is no open popup yet. + verify(!listView()); + // Click in the input field. + var browserInputCenter = getElementCenter("browserInput"); + mouseClick(webEngineView, browserInputCenter.x, browserInputCenter.y, Qt.LeftButton); + // Wait for the popup. + tryVerify(function() { return listView() != null; }); + + // No suggestion is selected. + verify(!listView().currentItem); + compare(listView().count, 5); + + // Accepting suggestion does nothing. + keyClick(Qt.Key_Enter); + tryVerify(function() { return listView() != null; }); + verify(!listView().currentItem); + + // Escape should close popup. + keyClick(Qt.Key_Escape); + tryVerify(function() { return listView() == null; }); + + // Key Down should open the popup and select the first suggestion. + keyClick(Qt.Key_Down); + tryVerify(function() { return listView() != null; }); + compare(listView().currentIndex, 0); + verify(listView().currentItem); + } + + function test_keyboardNavigationAndAccept() { + webEngineView.loadHtml(html); + verify(webEngineView.waitForLoadSucceeded()); + setFocusToElement("browserInput"); + + // Make sure there is no open popup yet. + verify(!listView()); + + // Key Down should open the popup and select the first suggestion. + keyClick(Qt.Key_Down); + tryVerify(function() { return listView() != null; }); + compare(listView().currentIndex, 0); + + // Test keyboard navigation in list. + keyClick(Qt.Key_Up); + compare(listView().currentIndex, 4); + keyClick(Qt.Key_Up); + compare(listView().currentIndex, 3); + keyClick(Qt.Key_PageDown); + compare(listView().currentIndex, 4); + keyClick(Qt.Key_PageUp); + compare(listView().currentIndex, 0); + keyClick(Qt.Key_Down); + compare(listView().currentIndex, 1); + keyClick(Qt.Key_Down); + compare(listView().currentIndex, 2); + + // Test accepting suggestion. + compare(listView().currentItem.text, "Chrome"); + keyClick(Qt.Key_Enter); + compareElementValue("browserInput", "Chrome"); + // Accept closes popup. + tryVerify(function() { return listView() == null; }); + + // Clear input field, should not trigger popup. + webEngineView.runJavaScript("document.getElementById('browserInput').value = ''"); + compareElementValue("browserInput", ""); + verify(listView() == null); + } + + function test_filterSuggestion() { + webEngineView.loadHtml(html); + verify(webEngineView.waitForLoadSucceeded()); + setFocusToElement("browserInput"); + + // Make sure there is no open popup yet. + verify(!listView()); + + // Filter suggestions. + keyClick(Qt.Key_F); + tryVerify(function() { return listView() != null; }); + compare(listView().count, 2); + verify(!listView().currentItem); + compare(listView().itemAtIndex(0).text, "Firefox"); + compare(listView().itemAtIndex(1).text, "Safari"); + keyClick(Qt.Key_I); + tryVerify(function() { return listView().count == 1; }); + verify(!listView().currentItem); + compare(listView().itemAtIndex(0).text, "Firefox"); + keyClick(Qt.Key_L); + // Mismatch should close popup. + tryVerify(function() { return listView() == null; }); + compareElementValue("browserInput", "fil"); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml b/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml index 780294348..6cb2841ec 100644 --- a/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml +++ b/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -44,7 +19,7 @@ TestWebEngineView { signalName: "linkHovered" } - onLinkHovered: { + onLinkHovered: function(hoveredUrl) { webEngineView.lastUrl = hoveredUrl } diff --git a/tests/auto/quick/qmltests/data/tst_download.qml b/tests/auto/quick/qmltests/data/tst_download.qml index 1b1750dd8..61a363c39 100644 --- a/tests/auto/quick/qmltests/data/tst_download.qml +++ b/tests/auto/quick/qmltests/data/tst_download.qml @@ -1,36 +1,11 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.10 -import Qt.labs.platform 1.0 -import Test.util 1.0 +import QtQuick +import QtTest +import QtWebEngine +import Qt.labs.platform +import Test.util TestWebEngineView { id: webEngineView @@ -51,7 +26,6 @@ TestWebEngineView { property string downloadedSetPath: "" property int downloadDirectoryChanged: 0 property int downloadFileNameChanged: 0 - property int downloadPathChanged: 0 property bool setDirectoryFirst: false TempDir { id: tempDir } @@ -80,17 +54,24 @@ TestWebEngineView { Connections { id: downloadItemConnections ignoreUnknownSignals: true - onStateChanged: downloadState.push(target.state) - onInterruptReasonChanged: downloadInterruptReason = target.interruptReason - onDownloadDirectoryChanged: downloadDirectoryChanged++ - onDownloadFileNameChanged: downloadFileNameChanged++ - onPathChanged: downloadPathChanged++ + function onStateChanged() { + downloadState.push(target.state); + } + function onInterruptReasonChanged() { + downloadInterruptReason = target.interruptReason; + } + function onDownloadDirectoryChanged() { + downloadDirectoryChanged++; + } + function onDownloadFileNameChanged() { + downloadFileNameChanged++; + } } WebEngineProfile { id: testDownloadProfile - onDownloadRequested: { + onDownloadRequested: function(download) { testDownloadProfile.downloadPath = tempDir.path() downloadState.push(download.state) downloadItemConnections.target = download @@ -120,7 +101,7 @@ TestWebEngineView { downloadUrl = download.url suggestedFileName = download.suggestedFileName } - onDownloadFinished: { + onDownloadFinished: function(download) { receivedBytes = download.receivedBytes; } } @@ -139,7 +120,6 @@ TestWebEngineView { downloadInterruptReason = null downloadDirectoryChanged = 0 downloadFileNameChanged = 0 - downloadPathChanged = 0 downloadDirectory = "" downloadFileName = "" downloadedPath = "" @@ -155,7 +135,7 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 1) compare(downloadUrl, webEngineView.url) compare(suggestedFileName, "download.zip") - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested) verify(!downloadInterruptReason) } @@ -179,11 +159,11 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 1) compare(downloadUrl, webEngineView.url) compare(suggestedFileName, "download.zip") - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress) + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested) + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadInProgress) downloadFinishedSpy.wait() compare(totalBytes, receivedBytes) - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted) + tryCompare(downloadState, "2", WebEngineDownloadRequest.DownloadCompleted) verify(!downloadInterruptReason) } @@ -196,8 +176,8 @@ TestWebEngineView { compare(downloadUrl, webEngineView.url) compare(suggestedFileName, "download.zip") compare(downloadFinishedSpy.count, 1) - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadCancelled) - tryCompare(webEngineView, "downloadInterruptReason", WebEngineDownloadItem.UserCanceled) + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadCancelled) + tryCompare(webEngineView, "downloadInterruptReason", WebEngineDownloadRequest.UserCanceled) } function test_downloadLocation() { @@ -230,15 +210,14 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 1); compare(downloadUrl, webEngineView.url); compare(suggestedFileName, "download.zip"); - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested); + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadInProgress); compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + downloadFileName); compare(downloadDirectoryChanged, 1); compare(downloadFileNameChanged, 1); - compare(downloadPathChanged, 2); downloadFinishedSpy.wait(); compare(totalBytes, receivedBytes); - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); + tryCompare(downloadState, "2", WebEngineDownloadRequest.DownloadCompleted); verify(!downloadInterruptReason); } @@ -253,15 +232,14 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 1); compare(downloadUrl, webEngineView.url); compare(suggestedFileName, "download.zip"); - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested); + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadInProgress); compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + "download.zip"); compare(downloadDirectoryChanged, 1); compare(downloadFileNameChanged, 0); - compare(downloadPathChanged, 1); downloadFinishedSpy.wait(); compare(totalBytes, receivedBytes); - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); + tryCompare(downloadState, "2", WebEngineDownloadRequest.DownloadCompleted); verify(!downloadInterruptReason); // Download the same file to another directory with suggested file name. @@ -270,22 +248,20 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 0); downloadDirectoryChanged = 0; downloadFileNameChanged = 0; - downloadPathChanged = 0; downloadDirectory = "/test_downloadToDirectoryWithSuggestedFileName1/"; webEngineView.url = Qt.resolvedUrl("download.zip"); downLoadRequestedSpy.wait(); compare(downLoadRequestedSpy.count, 1); compare(downloadUrl, webEngineView.url); compare(suggestedFileName, "download.zip"); - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested); + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadInProgress); compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + "download.zip"); compare(downloadDirectoryChanged, 1); compare(downloadFileNameChanged, 0); - compare(downloadPathChanged, 1); downloadFinishedSpy.wait(); compare(totalBytes, receivedBytes); - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); + tryCompare(downloadState, "2", WebEngineDownloadRequest.DownloadCompleted); verify(!downloadInterruptReason); // Download same file to same directory second time -> file name should be unified. @@ -294,44 +270,20 @@ TestWebEngineView { compare(downLoadRequestedSpy.count, 0); downloadDirectoryChanged = 0; downloadFileNameChanged = 0; - downloadPathChanged = 0; downloadDirectory = "/test_downloadToDirectoryWithSuggestedFileName1/"; webEngineView.url = Qt.resolvedUrl("download.zip"); downLoadRequestedSpy.wait(); compare(downLoadRequestedSpy.count, 1); compare(downloadUrl, webEngineView.url); compare(suggestedFileName, "download.zip"); - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested); + tryCompare(downloadState, "1", WebEngineDownloadRequest.DownloadInProgress); compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + "download (1).zip"); compare(downloadDirectoryChanged, 1); compare(downloadFileNameChanged, 1); - compare(downloadPathChanged, 1); - downloadFinishedSpy.wait(); - compare(totalBytes, receivedBytes); - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); - verify(!downloadInterruptReason); -} - - function test_downloadWithSetPath() { - compare(downLoadRequestedSpy.count, 0); - compare(downloadDirectoryChanged, 0); - compare(downloadFileNameChanged, 0); - downloadedSetPath = "/test_downloadWithSetPath/test.zip"; - webEngineView.url = Qt.resolvedUrl("download.zip"); - downLoadRequestedSpy.wait(); - compare(downLoadRequestedSpy.count, 1); - compare(downloadUrl, webEngineView.url); - compare(suggestedFileName, "download.zip"); - compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); - tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); - compare(downloadedPath, testDownloadProfile.downloadPath + downloadedSetPath); - compare(downloadDirectoryChanged, 1); - compare(downloadFileNameChanged, 1); - compare(downloadPathChanged, 2); downloadFinishedSpy.wait(); compare(totalBytes, receivedBytes); - tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); + tryCompare(downloadState, "2", WebEngineDownloadRequest.DownloadCompleted); verify(!downloadInterruptReason); } } diff --git a/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml b/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml new file mode 100644 index 000000000..c22bd44c2 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml @@ -0,0 +1,67 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +Item { + id: parentItem + width: 400 + height: 300 + + Rectangle { + id: draggableDownUnder + color: "wheat" + width: 350 + height: 250 + + DragHandler { id: dragHandler } + } + + TestWebEngineView { + id: webEngineView + width: 300 + height: 250 + + property var testUrl: Qt.resolvedUrl("test4.html") + + SignalSpy { + id: scrollPositionSpy + target: webEngineView + signalName: "onScrollPositionChanged" + } + + SignalSpy { + id: dragActiveSpy + target: dragHandler + signalName: "activeChanged" + } + + TestCase { + id: testCase + name: "KeepMouseGrabDuringScrolling" + when: windowShown + + function test_scroll() { + webEngineView.url = Qt.resolvedUrl("test4.html"); + verify(webEngineView.waitForLoadSucceeded()); + + mousePress(webEngineView, 295, 20); + mouseMove(webEngineView, 295, 200); + mouseRelease(webEngineView, 295, 200); + + // WebEngineView scrolled if the scrollbar was visible. + // But on macOS, the scrollbar is hidden, so text gets selected. + tryVerify(function() { + return (scrollPositionSpy.count === 1 && webEngineView.scrollPosition.y > 100) + || webEngineView.getTextSelection().length > 0; + }); + + // DragHandler didn't take over and drag + compare(dragActiveSpy.count, 0); + compare(draggableDownUnder.y, 0); + } + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml new file mode 100644 index 000000000..15f116e5d --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_favicon.qml @@ -0,0 +1,527 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + TempDir { id: tempDir } + + property QtObject defaultProfile: WebEngineProfile { + offTheRecord: true + } + + property QtObject nonOTRProfile: WebEngineProfile { + persistentStoragePath: tempDir.path() + '/WebEngineFavicon' + offTheRecord: false + } + + function removeFaviconProviderPrefix(url) { + return url.toString().substring(16) + } + + SignalSpy { + id: iconChangedSpy + target: webEngineView + signalName: "iconChanged" + } + + Image { + id: favicon + source: webEngineView.icon + } + + TestCase { + id: testCase + name: "WebEngineFavicon" + when: windowShown + + + function init() { + // It is worth to restore the initial state with loading a blank page before all test functions. + webEngineView.url = 'about:blank'; + verify(webEngineView.waitForLoadSucceeded()); + iconChangedSpy.clear(); + webEngineView.settings.touchIconsEnabled = false; + webEngineView.settings.autoLoadIconsForPage = true; + } + + function test_faviconLoad_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoad(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("favicon.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } + + function test_faviconLoadEncodedUrl_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoadEncodedUrl(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("favicon2.html?favicon=load should work with#whitespace!") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } + + function test_faviconLoadAfterHistoryNavigation_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoadAfterHistoryNavigation(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var iconUrl + + webEngineView.url = Qt.resolvedUrl("favicon.html") + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 1) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")) + + iconChangedSpy.clear() + webEngineView.url = Qt.resolvedUrl("favicon-shortcut.html") + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + + iconChangedSpy.clear() + webEngineView.goBack(); + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")) + + iconChangedSpy.clear() + webEngineView.goForward(); + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + } + + function test_faviconLoadPushState_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoadPushState(row) { + webEngineView.profile = row.profile; + compare(iconChangedSpy.count, 0); + + var iconUrl; + + webEngineView.url = Qt.resolvedUrl("favicon.html"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(iconChangedSpy, "count", 1); + iconUrl = removeFaviconProviderPrefix(webEngineView.icon); + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")); + + iconChangedSpy.clear(); + + // pushState() is a same document navigation and should not reset or + // update favicon. + compare(webEngineView.history.items.rowCount(), 1); + runJavaScript("history.pushState('', '')"); + tryVerify(function() { return webEngineView.history.items.rowCount() === 2; }); + + // Favicon change is not expected. + compare(iconChangedSpy.count, 0); + iconUrl = removeFaviconProviderPrefix(webEngineView.icon); + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")); + } + + function test_noFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_noFavicon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("test1.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_aboutBlank_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_aboutBlank(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("about:blank") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_unavailableFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_unavailableFavicon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("favicon-unavailable.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_errorPageEnabled_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_errorPageEnabled(row) { + webEngineView.profile = row.profile + webEngineView.settings.errorPageEnabled = true + + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("http://url.invalid") + webEngineView.url = url + verify(webEngineView.waitForLoadFailed(20000)) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_errorPageDisabled_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_errorPageDisabled(row) { + webEngineView.profile = row.profile + webEngineView.settings.errorPageEnabled = false + + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("http://url.invalid") + webEngineView.url = url + verify(webEngineView.waitForLoadFailed(20000)) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_bestFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_bestFavicon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + var url, iconUrl + + url = Qt.resolvedUrl("favicon-misc.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + // Touch icon is ignored + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + + iconChangedSpy.clear() + + url = Qt.resolvedUrl("favicon-shortcut.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + + // If touch icon is disabled, FaviconHandler propagates the icon closest to size 16x16 + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } + + function test_touchIcon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_touchIcon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("favicon-touch.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + compare(favicon.width, 0) + compare(favicon.height, 0) + + webEngineView.settings.touchIconsEnabled = true + + url = Qt.resolvedUrl("favicon-touch.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/qt144.png")) + compare(iconChangedSpy.count, 1) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 144) + compare(favicon.height, 144) + } + + function test_multiIcon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_multiIcon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var url = Qt.resolvedUrl("favicon-multi.html") + webEngineView.url = url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } + + function test_dynamicFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_dynamicFavicon(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var faviconImage = Qt.createQmlObject(" + import QtQuick\n + Image { width: 16; height: 16; sourceSize: Qt.size(width, height); objectName: 'image' }", testCase) + faviconImage.source = Qt.binding(function() { return webEngineView.icon; }); + + var colors = [ + {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==", "r": 255, "g": 0, "b": 0}, + {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==", "r": 0, "g": 255, "b": 0}, + {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==", "r": 0, "g": 0, "b": 255}, + ]; + var pixel; + + compare(iconChangedSpy.count, 0); + webEngineView.loadHtml( + "<html>" + + "<link rel='icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>" + + "</html>" + ); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(iconChangedSpy, "count", 1); + + pixel = getItemPixel(faviconImage); + compare(pixel[0], 0); + compare(pixel[1], 0); + compare(pixel[2], 0); + + for (var i = 0; i < colors.length; ++i) { + iconChangedSpy.clear(); + runJavaScript("document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[i]["url"] + "';"); + tryCompare(faviconImage, "source", "image://favicon/data:image/png;base64," + colors[i]["url"]); + compare(iconChangedSpy.count, 1); + + pixel = getItemPixel(faviconImage); + compare(pixel[0], colors[i]["r"]); + compare(pixel[1], colors[i]["g"]); + compare(pixel[2], colors[i]["b"]); + } + + faviconImage.destroy() + } + + function test_touchIconWithSameURL_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_touchIconWithSameURL(row) + { + webEngineView.profile = row.profile; + compare(iconChangedSpy.count, 0); + + var icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="; + + webEngineView.loadHtml( + "<html>" + + "<link rel='icon' type='image/png' href='" + icon + "'/>" + + "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>" + + "</html>" + ); + verify(webEngineView.waitForLoadSucceeded()); + + // The default favicon has to be loaded even if its URL is also set as a touch icon while touch icons are disabled. + tryCompare(iconChangedSpy, "count", 1); + compare(webEngineView.icon.toString().replace(/^image:\/\/favicon\//, ''), icon); + + iconChangedSpy.clear(); + + webEngineView.loadHtml( + "<html>" + + "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>" + + "</html>" + ); + verify(webEngineView.waitForLoadSucceeded()); + + // 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. + tryCompare(iconChangedSpy, "count", 1); + verify(!webEngineView.icon.toString().replace(/^image:\/\/favicon\//, '')); + } + + function test_iconsDisabled_data() { + return [ + { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html") }, + { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html") }, + { tag: "single", url: Qt.resolvedUrl("favicon-single.html") }, + { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html") }, + { tag: "unavailable", url: Qt.resolvedUrl("favicon-unavailable.html") }, + ]; + } + + function test_iconsDisabled(row) { + webEngineView.settings.autoLoadIconsForPage = false + webEngineView.profile = defaultProfile + compare(iconChangedSpy.count, 0) + + webEngineView.url = row.url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_touchIconsEnabled_data() { + return [ + { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + { tag: "single", url: Qt.resolvedUrl("favicon-single.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt32.ico") }, + { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + ]; + } + + function test_touchIconsEnabled(row) { + webEngineView.settings.touchIconsEnabled = true + webEngineView.profile = defaultProfile + compare(iconChangedSpy.count, 0) + + webEngineView.url = row.url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + + var iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, row.expectedIconUrl) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml b/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml new file mode 100644 index 000000000..284390619 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml @@ -0,0 +1,216 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + TempDir { id: tempDir } + + property QtObject defaultProfile: WebEngineProfile { + offTheRecord: true + } + + property QtObject nonOTRProfile: WebEngineProfile { + persistentStoragePath: tempDir.path() + '/WebEngineFavicon' + offTheRecord: false + } + + function getFaviconPixel(faviconImage) { + var grabImage = Qt.createQmlObject(" + import QtQuick\n + Image { }", testCase) + var faviconCanvas = Qt.createQmlObject(" + import QtQuick\n + Canvas { }", testCase) + + testCase.tryVerify(function() { return faviconImage.status == Image.Ready }); + faviconImage.grabToImage(function(result) { + grabImage.source = result.url + }); + testCase.tryVerify(function() { return grabImage.status == Image.Ready }); + + faviconCanvas.width = faviconImage.width; + faviconCanvas.height = faviconImage.height; + var ctx = faviconCanvas.getContext("2d"); + ctx.drawImage(grabImage, 0, 0, grabImage.width, grabImage.height); + var imageData = ctx.getImageData(Math.round(faviconCanvas.width/2), + Math.round(faviconCanvas.height/2), + faviconCanvas.width, + faviconCanvas.height); + + grabImage.destroy(); + faviconCanvas.destroy(); + + return imageData.data; + } + + SignalSpy { + id: iconChangedSpy + target: webEngineView + signalName: "iconChanged" + } + + TestCase { + id: testCase + name: "WebEngineFaviconDatabase" + when: windowShown + + function init() { + // It is worth to restore the initial state with loading a blank page before all test functions. + webEngineView.url = 'about:blank'; + verify(webEngineView.waitForLoadSucceeded()); + iconChangedSpy.clear(); + webEngineView.settings.touchIconsEnabled = false; + webEngineView.settings.autoLoadIconsForPage = true; + } + + function cleanupTestCase() { + tempDir.removeRecursive(nonOTRProfile.persistentStoragePath); + } + + function test_iconDatabase_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_iconDatabase(row) + { + if (Screen.devicePixelRatio !== 1.0) + skip("This test is not supported on High DPI screens."); + + webEngineView.profile = row.profile; + compare(iconChangedSpy.count, 0); + + var faviconImage = Qt.createQmlObject(" + import QtQuick\n + Image { width: 16; height: 16; sourceSize: Qt.size(width, height); cache: false; }", testCase); + + var pixel; + compare(iconChangedSpy.count, 0); + + webEngineView.url = Qt.resolvedUrl("favicon.html"); // favicon.png -> 165 + verify(webEngineView.waitForLoadSucceeded()); + + iconChangedSpy.wait(); + compare(iconChangedSpy.count, 1); + + var previousIcon = webEngineView.icon; + iconChangedSpy.clear(); + + webEngineView.url = Qt.resolvedUrl("favicon-shortcut.html"); // qt32.ico -> 251 + verify(webEngineView.waitForLoadSucceeded()); + + tryCompare(iconChangedSpy, "count", 2); + + // Icon database is not accessible with OTR profile. + faviconImage.source = previousIcon; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], webEngineView.profile.offTheRecord ? 0 : 165); + + // This should pass with OTR too because icon is requested for the current page. + faviconImage.source = "image://favicon/" + Qt.resolvedUrl("favicon-shortcut.html"); + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 251); + + faviconImage.source = "image://favicon/" + Qt.resolvedUrl("favicon.html"); + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], webEngineView.profile.offTheRecord ? 0 : 165); + + faviconImage.destroy(); + webEngineView.profile = defaultProfile; + } + + function test_iconDatabaseMultiView() + { + if (Screen.devicePixelRatio !== 1.0) + skip("This test is not supported on High DPI screens."); + + var pixel; + + var faviconImage = Qt.createQmlObject(" + import QtQuick\n + Image { width: 16; height: 16; sourceSize: Qt.size(width, height); cache: false; }", testCase); + + var webEngineView1 = Qt.createQmlObject(" + import QtWebEngine\n + import Test.util\n + import '../../qmltests/data'\n + TestWebEngineView {\n + TempDir { id: tempDir } + profile: WebEngineProfile {\n + persistentStoragePath: tempDir.path() + '/WebEngineFavicon1'\n + offTheRecord: false\n + }\n + }", testCase); + + var webEngineView2 = Qt.createQmlObject(" + import QtWebEngine\n + import Test.util\n + import '../../qmltests/data'\n + TestWebEngineView {\n + TempDir { id: tempDir } + profile: WebEngineProfile {\n + persistentStoragePath: tempDir.path() + '/WebEngineFavicon2'\n + offTheRecord: false\n + }\n + }", testCase); + + // Moke sure the icons have not been stored in the database yet. + var icon1 = "image://favicon/" + Qt.resolvedUrl("icons/favicon.png"); + faviconImage.source = icon1; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 0); + + var icon2 = "image://favicon/" + Qt.resolvedUrl("icons/qt32.ico"); + faviconImage.source = icon2; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 0); + + webEngineView1.url = Qt.resolvedUrl("favicon.html"); // favicon.png -> 165 + verify(webEngineView1.waitForLoadSucceeded()); + tryCompare(webEngineView1, "icon", icon1); + webEngineView1.url = "about:blank"; + verify(webEngineView1.waitForLoadSucceeded()); + + webEngineView2.url = Qt.resolvedUrl("favicon-shortcut.html"); // qt32.ico -> 251 + verify(webEngineView2.waitForLoadSucceeded()); + tryCompare(webEngineView2, "icon", icon2); + webEngineView2.url = "about:blank"; + verify(webEngineView2.waitForLoadSucceeded()); + + faviconImage.source = ""; + compare(webEngineView1.icon, ""); + compare(webEngineView2.icon, ""); + + faviconImage.source = icon1; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 165); + + faviconImage.source = icon2; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 251); + + faviconImage.source = "image://favicon/file:///does.not.exist.ico"; + pixel = getFaviconPixel(faviconImage); + compare(pixel[0], 0); + + webEngineView1.destroy(); + webEngineView2.destroy(); + faviconImage.destroy(); + + tempDir.removeRecursive(webEngineView1.profile.persistentStoragePath) + tempDir.removeRecursive(webEngineView2.profile.persistentStoragePath) + } + } +} + diff --git a/tests/auto/quick/qmltests/data/tst_filePicker.qml b/tests/auto/quick/qmltests/data/tst_filePicker.qml new file mode 100644 index 000000000..a7b59b2e9 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_filePicker.qml @@ -0,0 +1,297 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import "../../qmltests/data" +import "../mock-delegates/TestParams" + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + function driveLetter() { + if (Qt.platform.os !== "windows") + return ""; + return "C:/"; + } + + SignalSpy { + id: titleSpy + target: webEngineView + signalName: "titleChanged" + } + SignalSpy { + id: terminationSpy + target: webEngineView + signalName: "renderProcessTerminated" + } + + TestCase { + id: testCase + name: "WebEngineViewSingleFileUpload" + when: windowShown + + function init() { + FilePickerParams.filePickerOpened = false + FilePickerParams.selectFiles = false + FilePickerParams.selectedFilesUrl = [] + FilePickerParams.nameFilters = [] + titleSpy.clear() + terminationSpy.clear() + } + + function cleanup() { + // Test that the render process doesn't crash, and make sure if it does it does so now. + wait(100) + verify(terminationSpy.count == 0, "Render process didn't self terminate") + + // FIXME: Almost every second url loading progress does get stuck at about 90 percent, so the loadFinished signal won't arrive. + // This cleanup function is a workaround for this problem. + webEngineView.url = Qt.resolvedUrl("about:blank") + webEngineView.waitForLoadSucceeded() + } + + function test_acceptSingleFileSelection_data() { + return [ + { tag: "test.txt", input: "test.txt", expected: "Failed to Upload" }, + { tag: driveLetter() + "/test.txt", input: driveLetter() + "/test.txt", expected: "test.txt" }, + { tag: driveLetter() + "/tést.txt", input: driveLetter() + "/tést.txt", expected: "tést.txt" }, + { tag: driveLetter() + "/t%65st.txt", input: driveLetter() + "/t%65st.txt", expected: "t%65st.txt" }, + { tag: "file:///" + driveLetter() + "test.txt", input: "file:///" + driveLetter() + "test.txt", expected: "test.txt" }, + { tag: "file:///" + driveLetter() + "tést.txt", input: "file:///" + driveLetter() + "tést.txt", expected: "tést.txt" }, + { tag: "file:///" + driveLetter() + "t%65st.txt", input: "file:///" + driveLetter() + "t%65st.txt", expected: "t%65st.txt" }, + { tag: "file://" + driveLetter() + "test.txt", input: "file://" + driveLetter() + "test.txt", expected: "Failed to Upload" }, + { tag: "file:/" + driveLetter() + "test.txt", input: "file:/" + driveLetter() + "test.txt", expected: "test.txt"}, + { tag: "file:test//test.txt", input: "file:test//test.txt", expected: "Failed to Upload" }, + { tag: "http://test.txt", input: "http://test.txt", expected: "Failed to Upload" }, + { tag: "qrc:/test.txt", input: "qrc:/test.txt", expected: "Failed to Upload" }, + ]; + } + + function test_acceptSingleFileSelection(row) { + var expectedFileName; + + // Default dialog + webEngineView.url = Qt.resolvedUrl("singlefileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(row.input); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + + + // Custom dialog + var finished = false; + + function acceptedFileHandler(request) { + request.accepted = true; + request.dialogAccept([row.input]); + finished = true; + } + + webEngineView.fileDialogRequested.connect(acceptedFileHandler); + webEngineView.url = Qt.resolvedUrl("singlefileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryVerify(function() { return finished; }); + tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); + } + + function test_acceptMultipleFilesSelection() { + webEngineView.url = Qt.resolvedUrl("multifileupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + FilePickerParams.selectFiles = true + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("test1.html")) + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("test2.html")) + + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true) + tryCompare(webEngineView, "title", "test1.html,test2.html") + } + + function test_acceptDirectory() { + webEngineView.url = Qt.resolvedUrl("directoryupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.runJavaScript( + "let relativePathCount = 0;" + + "document.getElementById('upfile').addEventListener('change', function(event) {" + + " let files = event.target.files;" + + " for (let i = 0; i < files.length; i++) {" + + " if (files[i].webkitRelativePath != '')" + + " relativePathCount++;" + + " }" + + "}, false);") + + FilePickerParams.selectFiles = true + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("../data")) + + keyClick(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "directoryPickerOpened", true) + // Check that the title is a file list (eg. "test1.html,test2.html") + tryVerify(function() { return webEngineView.title.match("^([^,]+,)+[^,]+$"); }) + + var relativePathCount = 0; + runJavaScript("relativePathCount", function(result) { relativePathCount = result; }); + // The number of files in data directory may vary + tryVerify(function() { return relativePathCount > 0; }); + } + + function test_reject() { + webEngineView.url = Qt.resolvedUrl("singlefileupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + titleSpy.clear() + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + wait(100) + compare(titleSpy.count, 0) + } + + function test_acceptMultipleFilesWithCustomDialog_data() { + return [ + { tag: "path", input: [driveLetter() + "/test1.txt", driveLetter() + "/test2.txt"], expectedValue: "test1.txt,test2.txt" }, + { tag: "file", input: ["file:///" + driveLetter() + "test1.txt", "file:/" + driveLetter() + "test2.txt"], expectedValue: "test1.txt,test2.txt" }, + { tag: "mixed", input: ["file:///" + driveLetter() + "test1.txt", driveLetter() + "/test2.txt"], expectedValue: "test1.txt,test2.txt" }, + ]; + } + + function test_acceptMultipleFilesWithCustomDialog(row) { + // Default dialog + webEngineView.url = Qt.resolvedUrl("multifileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl = row.input; + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryCompare(webEngineView, "title", row.expectedValue); + + + // Custom dialog + var finished = false; + + function acceptedFileHandler(request) { + request.accepted = true; + request.dialogAccept(row.input); + finished = true; + } + + webEngineView.fileDialogRequested.connect(acceptedFileHandler); + webEngineView.url = Qt.resolvedUrl("multifileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryVerify(function() { return finished; }); + tryCompare(webEngineView, "title", row.expectedValue); + webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); + } + + function test_acceptFileOnWindows_data() { + return [ + { tag: "C:test.txt", input: "C:test.txt", expected: "Failed to Upload"}, + { tag: "C:test:txt", input: "C:test:txt", expected: "Failed to Upload"}, + { tag: "C:/test.txt", input: "C:/test.txt", expected: "test.txt"}, + { tag: "C:\\test.txt", input: "C:\\test.txt", expected: "test.txt"}, + { tag: "C:\\Documents and Settings\\test\\test.txt", input: "C:\\Documents and Settings\\test\\test.txt", expected: "test.txt"}, + { tag: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", input: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", expected: "test.txt"}, + { tag: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"}, + { tag: "file://applib/products/a-b/abc_1/t.est/test.txt", input: "file://applib/products/a-b/abc_1/t.est/test.txt", expected: "test.txt"}, + { tag: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", input: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", expected: "test.txt"}, + { tag: "file:C:/test.txt", input: "file:C:/test.txt", expected: "test.txt"}, + { tag: "file:/C:/test.txt", input: "file:/C:/test.txt", expected: "test.txt"}, + { tag: "file://C:/test.txt", input: "file://C:/test.txt", expected: "Failed to Upload"}, + { tag: "file:///C:test.txt", input: "file:///C:test.txt", expected: "Failed to Upload"}, + { tag: "file:///C:/test.txt", input: "file:///C:/test.txt", expected: "test.txt"}, + { tag: "file:///C:\\test.txt", input: "file:///C:\\test.txt", expected: "test.txt"}, + { tag: "file:\\//C:/test.txt", input: "file:\\//C:/test.txt", expected: "test.txt"}, + { tag: "file:\\\\/C:\\test.txt", input: "file:\\\\/C:\\test.txt", expected: "test.txt"}, + { tag: "\\\\?\\C:/test.txt", input: "\\\\?\\C:/test.txt", expected: "test.txt"}, + ]; + } + + function test_acceptFileOnWindows(row) { + if (Qt.platform.os !== "windows") + skip("Windows-only test"); + + // Default dialog + webEngineView.url = Qt.resolvedUrl("singlefileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(row.input); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + + + // Custom dialog + var finished = false; + + function acceptedFileHandler(request) { + request.accepted = true; + request.dialogAccept([row.input]); + finished = true; + } + + webEngineView.fileDialogRequested.connect(acceptedFileHandler); + webEngineView.url = Qt.resolvedUrl("singlefileupload.html"); + verify(webEngineView.waitForLoadSucceeded()); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryVerify(function() { return finished; }); + tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); + } + + function test_acceptFileTypes_data() { + return [ + { tag: "CustomSuffix", input: ".pug", expected: ".pug", exactMatch: false}, + { tag: "CustomMime", input: "dog/pug", expected: "Accepted types ()", exactMatch: true}, + { tag: "CustomGlob", input: "dog/*", expected: "Accepted types ()", exactMatch: true}, + { tag: "Invalid", input: "---", expected: undefined, exactMatch: true}, + { tag: "Jpeg", input: "image/jpeg", expected: ".jpeg", exactMatch: false} + ]; + } + + function test_acceptFileTypes(row) { + var expectedFileName; + + webEngineView.url = Qt.resolvedUrl("accepttypes.html"); + verify(webEngineView.waitForLoadSucceeded()); + + webEngineView.runJavaScript("setAcceptType('" + row.input + "');"); + tryCompare(webEngineView, "title", row.input); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + + if (row.exactMatch) + compare(FilePickerParams.nameFilters[0], row.expected); + else + verify(FilePickerParams.nameFilters[0].includes(row.expected)); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_filesystem.qml b/tests/auto/quick/qmltests/data/tst_filesystem.qml new file mode 100644 index 000000000..fa0da4457 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_filesystem.qml @@ -0,0 +1,124 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" +import "../mock-delegates/TestParams" + + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + property var logs: [] + property bool accessRequested: false + property url file: tempDir.pathUrl('file.txt') + + onJavaScriptConsoleMessage: function(level, message, lineNumber, source) { + var pair = message.split(':'); + if (pair.length == 2 && pair[0] == "TEST") + logs.push(pair[1]); + } + + TempDir { id: tempDir } + + TestCase { + id: testCase + name: "FileSystemAPI" + when: windowShown + + function init() { + clearLog() + FilePickerParams.filePickerOpened = false + FilePickerParams.selectFiles = false + FilePickerParams.selectedFilesUrl = [] + FilePickerParams.nameFilters = [] + accessRequested = false; + } + + function cleanup() { + clearLog() + } + + function clearLog() { + logs = [] + } + + function logContainsDoneMarker() { + if (logs.indexOf("DONE") > -1) + return true + else + return false + } + + function result() { + return logs[0] + } + + function fileAccessRequest(request) { + testCase.verify(!accessRequested) + accessRequested = true + testCase.verify(request.filePath == file) + testCase.verify(request.accessFlags == WebEngineFileSystemAccessRequest.Write | WebEngineFileSystemAccessRequest.Read) + request.accept() + } + + function directoryAccessRequest(request) { + testCase.verify(!accessRequested) + accessRequested = true + testCase.verify(request.filePath == tempDir.pathUrl()) + testCase.verify(request.accessFlags == WebEngineFileSystemAccessRequest.Read) + request.accept() + } + + function test_saveFile() { + webEngineView.fileSystemAccessRequested.connect(fileAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=savePicker"); + verify(webEngineView.waitForLoadSucceeded()); + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(file); + keyClick(Qt.Key_Enter); // Open SaveDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + // write access for save dialogs is automatically granted + verify(!accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(fileAccessRequest); + } + + function test_openFile() { + // first save the file before open + test_saveFile() + init() + webEngineView.fileSystemAccessRequested.connect(fileAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=filePicker"); + verify(webEngineView.waitForLoadSucceeded()); + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(file); + keyClick(Qt.Key_Enter); // Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + verify(logs.indexOf("TEST_CONTENT") > -1) + verify(accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(fileAccessRequest); + } + + function test_selectDirectory() { + tempDir.createDirectory("TEST_DIR") + webEngineView.fileSystemAccessRequested.connect(directoryAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=directoryPicker"); + verify(webEngineView.waitForLoadSucceeded()) + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(tempDir.pathUrl()); + keyClick(Qt.Key_Enter); // Open showDirectoryDialog. + tryCompare(FilePickerParams, "directoryPickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + verify(logs.indexOf("TEST_DIR") > -1) + verify(accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(directoryAccessRequest); + } + + } +} diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml index c02a1348e..597cff73e 100644 --- a/tests/auto/quick/qmltests/data/tst_findText.qml +++ b/tests/auto/quick/qmltests/data/tst_findText.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -56,7 +31,7 @@ TestWebEngineView { // If this starts to fail then either clear was not called before findText // or unexpected callback was triggered from some search. // On c++ side callback id can be checked to verify - testcase.verify(!findCallbackCalled(), 'Unexpected callback call or uncleared state before findText call!') + testCase.verify(!findCallbackCalled(), 'Unexpected callback call or uncleared state before findText call!') webEngineView.matchCount = matchCount findFailed = matchCount == 0 @@ -64,7 +39,7 @@ TestWebEngineView { TestCase { - id: testcase + id: testCase name: "WebViewFindText" function getBodyInnerHTML() { @@ -231,8 +206,7 @@ TestWebEngineView { var listItemText = ''; for (var i = 0; i < 100000; ++i) - listItemText += "bla "; - listItemText = listItemText.trim(); + listItemText += "bla"; webEngineView.loadHtml( "<html><body>" + diff --git a/tests/auto/quick/qmltests/data/tst_focusOnNavigation.qml b/tests/auto/quick/qmltests/data/tst_focusOnNavigation.qml index 93410a727..f070e4bc5 100644 --- a/tests/auto/quick/qmltests/data/tst_focusOnNavigation.qml +++ b/tests/auto/quick/qmltests/data/tst_focusOnNavigation.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.5 -import QtTest 1.0 -import QtWebEngine 1.4 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine Item { id: container @@ -65,6 +40,7 @@ Item { } TestCase { + id: testCase name: "WebEngineViewFocusOnNavigation" when: windowShown diff --git a/tests/auto/quick/qmltests/data/tst_fullScreenRequest.qml b/tests/auto/quick/qmltests/data/tst_fullScreenRequest.qml index 2d9247b26..c7996a11e 100644 --- a/tests/auto/quick/qmltests/data/tst_fullScreenRequest.qml +++ b/tests/auto/quick/qmltests/data/tst_fullScreenRequest.qml @@ -1,6 +1,6 @@ -import QtQuick 2.2 -import QtTest 1.0 -import QtWebEngine 1.9 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: view diff --git a/tests/auto/quick/qmltests/data/tst_geopermission.qml b/tests/auto/quick/qmltests/data/tst_geopermission.qml index c935ac0b4..b99e50acc 100644 --- a/tests/auto/quick/qmltests/data/tst_geopermission.qml +++ b/tests/auto/quick/qmltests/data/tst_geopermission.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.2 -import QtTest 1.0 -import QtWebEngine 1.1 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -37,7 +12,6 @@ TestWebEngineView { property bool deniedGeolocation: false property bool geoPermissionRequested: false - signal consoleErrorMessage(string message) SignalSpy { id: featurePermissionSpy @@ -45,13 +19,7 @@ TestWebEngineView { signalName: "featurePermissionRequested" } - SignalSpy { - id: consoleErrorMessageSpy - target: webEngineView - signalName: "consoleErrorMessage" - } - - onFeaturePermissionRequested: { + onFeaturePermissionRequested: function(securityOrigin, feature) { if (feature === WebEngineView.Geolocation) { geoPermissionRequested = true if (deniedGeolocation) { @@ -63,19 +31,31 @@ TestWebEngineView { } } - onJavaScriptConsoleMessage: { - if (level === WebEngineView.ErrorMessageLevel) - consoleErrorMessage(message) - } - TestCase { name: "WebViewGeopermission" when: windowShown + function isHandled() { + var handled; + runJavaScript("handled", function(result) { + handled = result; + }); + tryVerify(function() { return handled != undefined; }, 5000); + return handled; + } + + function getErrorMessage() { + var errorMessage; + runJavaScript("errorMessage", function(result) { + errorMessage = result; + }); + tryVerify(function() { return errorMessage != undefined; }, 5000); + return errorMessage; + } + function init() { deniedGeolocation = false featurePermissionSpy.clear() - consoleErrorMessageSpy.clear() } function test_geoPermissionRequest() { @@ -84,17 +64,16 @@ TestWebEngineView { featurePermissionSpy.wait() verify(geoPermissionRequested) compare(featurePermissionSpy.count, 1) - consoleErrorMessageSpy.wait() - verify(consoleErrorMessageSpy.signalArguments[0][0] === "Success" || - consoleErrorMessageSpy.signalArguments[0][0] === "") + tryVerify(isHandled, 5000) + verify(getErrorMessage() === "") } function test_deniedGeolocationByUser() { deniedGeolocation = true webEngineView.url = Qt.resolvedUrl("geolocation.html") featurePermissionSpy.wait() - consoleErrorMessageSpy.wait() - compare(consoleErrorMessageSpy.signalArguments[0][0], "User denied Geolocation") + tryVerify(isHandled, 5000) + compare(getErrorMessage(), "User denied Geolocation") } } } diff --git a/tests/auto/quick/qmltests/data/tst_getUserMedia.qml b/tests/auto/quick/qmltests/data/tst_getUserMedia.qml index d1c894699..3b33b7abe 100644 --- a/tests/auto/quick/qmltests/data/tst_getUserMedia.qml +++ b/tests/auto/quick/qmltests/data/tst_getUserMedia.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtTest 1.0 -import QtWebEngine 1.6 +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -126,8 +101,8 @@ TestWebEngineView { signalName: "loadFinished" } - onLoadingChanged: { - if (loadRequest.status == WebEngineLoadRequest.LoadSucceededStatus) { + onLoadingChanged: function(load) { + if (load.status == WebEngineView.LoadSucceededStatus) { loadFinished() } } @@ -143,7 +118,7 @@ TestWebEngineView { property variant requestedFeature property variant requestedSecurityOrigin - onFeaturePermissionRequested: { + onFeaturePermissionRequested: function(securityOrigin, feature) { requestedFeature = feature requestedSecurityOrigin = securityOrigin } diff --git a/tests/auto/quick/qmltests/data/tst_inputMethod.qml b/tests/auto/quick/qmltests/data/tst_inputMethod.qml new file mode 100644 index 000000000..cf79e8a4d --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_inputMethod.qml @@ -0,0 +1,53 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + TestInputContext { id: testInputContext } + + TestCase { + id: testCase + name: "WebEngineViewInputMethod" + when: windowShown + + function init() { + testInputContext.create(); + } + + function cleanup() { + testInputContext.release(); + } + + function test_softwareInputPanel() { + verify(!Qt.inputMethod.visible); + webEngineView.loadHtml( + "<html><body>" + + " <form><input id='textInput' type='text' /></form>" + + "</body></html"); + verify(webEngineView.waitForLoadSucceeded()); + + verify(!getActiveElementId()); + verify(!Qt.inputMethod.visible); + + // Show input panel + webEngineView.runJavaScript("document.getElementById('textInput').focus()"); + webEngineView.verifyElementHasFocus("textInput"); + tryVerify(function() { return Qt.inputMethod.visible; }); + + // Hide input panel + webEngineView.runJavaScript("document.getElementById('textInput').blur()"); + verify(!getActiveElementId()); + tryVerify(function() { return !Qt.inputMethod.visible; }); + } + } +} + diff --git a/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml b/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml new file mode 100644 index 000000000..2141db4c8 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +TestWebEngineView { + id: webEngineView + width: 400 + height: 400 + + TestCase { + id: testCase + name: "WebEngineInputTextDirection" + when: windowShown + + function getInputTextDirection(element) { + var dir; + runJavaScript("document.getElementById('" + element + "').dir", function(result) { + dir = result; + }); + tryVerify(function() { return dir != undefined; }); + return dir; + } + + function test_changeInputTextDirection() { + webEngineView.loadHtml("<html><body><input type='text' id='textfield' value='some text'></body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + setFocusToElement("textfield"); + + var rtlAction = webEngineView.action(WebEngineView.ChangeTextDirectionRTL); + verify(rtlAction); + rtlAction.trigger(); + compare(getInputTextDirection("textfield"), "rtl"); + + var ltrAction = webEngineView.action(WebEngineView.ChangeTextDirectionLTR); + verify(ltrAction); + ltrAction.trigger(); + compare(getInputTextDirection("textfield"), "ltr"); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml b/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml new file mode 100644 index 000000000..6e91b2e77 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml @@ -0,0 +1,123 @@ +// Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import "../../qmltests/data" +import "../mock-delegates/TestParams" + +TestWebEngineView { + id: webEngineView + anchors.fill: parent + + property bool windowCloseRejectedCalled: false + + // Called by QQuickWebEngineViewPrivate::windowCloseRejected() + function windowCloseRejected() { + windowCloseRejectedCalled = true; + } + + TestCase { + id: test + name: "WebEngineViewJavaScriptDialogs" + when: windowShown + + function init() { + JSDialogParams.dialogMessage = ""; + JSDialogParams.dialogTitle = ""; + JSDialogParams.dialogCount = 0; + JSDialogParams.shouldAcceptDialog = true; + } + + function test_alert() { + webEngineView.url = Qt.resolvedUrl("alert.html") + verify(webEngineView.waitForLoadSucceeded()) + compare(JSDialogParams.dialogCount, 1) + compare(JSDialogParams.dialogMessage, "Hello Qt") + verify(JSDialogParams.dialogTitle.indexOf("Javascript Alert -") === 0) + } + + function test_confirm() { + webEngineView.url = Qt.resolvedUrl("confirm.html") + verify(webEngineView.waitForLoadSucceeded()) + compare(JSDialogParams.dialogMessage, "Confirm test") + compare(JSDialogParams.dialogCount, 1) + compare(webEngineView.title, "ACCEPTED") + JSDialogParams.shouldAcceptDialog = false + webEngineView.reload() + verify(webEngineView.waitForLoadSucceeded()) + compare(JSDialogParams.dialogCount, 2) + compare(webEngineView.title, "REJECTED") + + } + function readMousePressRecieved() { + var mousePressReceived; + runJavaScript("window.mousePressReceived", function(result) { + mousePressReceived = result; + }); + + _waitFor(function() { return mousePressReceived != undefined; }); + return mousePressReceived; + } + + function simulateUserGesture() { + // A user gesture after page load is required since Chromium 60 to allow showing + // an onbeforeunload dialog. + // See https://www.chromestatus.com/feature/5082396709879808 + mouseClick(webEngineView, 10, 10, Qt.LeftButton) + + tryVerify(readMousePressRecieved) + } + + function test_confirmClose() { + webEngineView.url = Qt.resolvedUrl("confirmclose.html"); + verify(webEngineView.waitForLoadSucceeded()); + webEngineView.windowCloseRequestedSignalEmitted = false; + JSDialogParams.shouldAcceptDialog = true; + + simulateUserGesture() + webEngineView.triggerWebAction(WebEngineView.RequestClose); + verify(webEngineView.waitForWindowCloseRequested()); + + // Navigate away from page with onbeforeunload handler, + // otherwise it would trigger an extra dialog request when + // navigating in the subsequent test. + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + compare(JSDialogParams.dialogCount, 2) + } + + function test_rejectClose() { + webEngineView.url = Qt.resolvedUrl("confirmclose.html"); + verify(webEngineView.waitForLoadSucceeded()); + webEngineView.windowCloseRejectedCalled = false; + JSDialogParams.shouldAcceptDialog = false; + + simulateUserGesture() + webEngineView.triggerWebAction(WebEngineView.RequestClose); + tryVerify(function() { return webEngineView.windowCloseRejectedCalled; }); + + // Navigate away from page with onbeforeunload handler, + // otherwise it would trigger an extra dialog request when + // navigating in the subsequent test. + JSDialogParams.shouldAcceptDialog = true; + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + compare(JSDialogParams.dialogCount, 2) + } + + function test_prompt() { + JSDialogParams.inputForPrompt = "tQ olleH" + webEngineView.url = Qt.resolvedUrl("prompt.html") + verify(webEngineView.waitForLoadSucceeded()) + compare(JSDialogParams.dialogCount, 1) + compare(webEngineView.title, "tQ olleH") + JSDialogParams.shouldAcceptDialog = false + webEngineView.reload() + verify(webEngineView.waitForLoadSucceeded()) + compare(JSDialogParams.dialogCount, 2) + compare(webEngineView.title, "null") + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml index 2536f319b..0f69a7e81 100644 --- a/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml +++ b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -36,6 +11,7 @@ TestWebEngineView { height: 480 TestCase { + id: testCase name: "WebEngineViewKeyboardEvents" when: windowShown @@ -53,20 +29,6 @@ TestWebEngineView { "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()); diff --git a/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml index e0a8c0a41..d0bc75619 100644 --- a/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml +++ b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_linkHovered.qml b/tests/auto/quick/qmltests/data/tst_linkHovered.qml new file mode 100644 index 000000000..a11bd2450 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_linkHovered.qml @@ -0,0 +1,108 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + focus: true + + property string lastUrl + + SignalSpy { + id: linkHoveredSpy + target: webEngineView + signalName: "linkHovered" + } + + onLinkHovered: function(hoveredUrl) { + webEngineView.lastUrl = hoveredUrl + } + + function isViewRendered() { + var pixel = getItemPixel(webEngineView); + + // The center pixel is expected to be red. + if (pixel[0] !== 255) return false; + if (pixel[1] !== 0) return false; + if (pixel[2] !== 0) return false; + + return true; + } + + TestCase { + id: testCase + name: "DesktopWebEngineViewLinkHovered" + + // Delayed windowShown to workaround problems with Qt5 in debug mode. + when: false + Timer { + running: parent.windowShown + repeat: false + interval: 1 + onTriggered: parent.when = true + } + + function init() { + webEngineView.lastUrl = ""; + linkHoveredSpy.clear(); + } + + function test_linkHovered() { + compare(linkHoveredSpy.count, 0); + mouseMove(webEngineView, 100, 300) + webEngineView.url = Qt.resolvedUrl("test2.html") + verify(webEngineView.waitForLoadSucceeded()) + + // We get a linkHovered signal with empty hoveredUrl after page load + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 1); + compare(webEngineView.lastUrl, "") + + // Wait for the page to be rendered before trying to test based on input events + tryVerify(isViewRendered); + + mouseMove(webEngineView, 100, 100) + linkHoveredSpy.wait(12000); + compare(linkHoveredSpy.count, 2); + compare(webEngineView.lastUrl, Qt.resolvedUrl("test1.html")) + mouseMove(webEngineView, 100, 300) + linkHoveredSpy.wait(12000); + compare(linkHoveredSpy.count, 3); + compare(webEngineView.lastUrl, "") + } + + function test_linkHoveredDoesntEmitRepeated() { + compare(linkHoveredSpy.count, 0); + webEngineView.url = Qt.resolvedUrl("test2.html") + verify(webEngineView.waitForLoadSucceeded()) + + // We get a linkHovered signal with empty hoveredUrl after page load + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 1); + compare(webEngineView.lastUrl, "") + + // Wait for the page to be rendered before trying to test based on input events + tryVerify(isViewRendered); + + for (var i = 0; i < 100; i += 10) + mouseMove(webEngineView, 100, 100 + i) + + linkHoveredSpy.wait(12000); + compare(linkHoveredSpy.count, 2); + compare(webEngineView.lastUrl, Qt.resolvedUrl("test1.html")) + + for (var i = 0; i < 100; i += 10) + mouseMove(webEngineView, 100, 300 + i) + + linkHoveredSpy.wait(12000); + compare(linkHoveredSpy.count, 3); + compare(webEngineView.lastUrl, "") + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_loadFail.qml b/tests/auto/quick/qmltests/data/tst_loadFail.qml new file mode 100644 index 000000000..8e9224bbf --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_loadFail.qml @@ -0,0 +1,79 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + property var unavailableUrl: Qt.resolvedUrl("file_that_does_not_exist.html") + + SignalSpy { + id: loadSpy + target: webEngineView + signalName: 'loadingChanged' + } + + TestCase { + id: test + name: "WebEngineViewLoadFail" + + function cleanup() { + loadSpy.clear() + } + + function test_fail() { + WebEngine.settings.errorPageEnabled = false + webEngineView.url = unavailableUrl + verify(webEngineView.waitForLoadFailed()) + } + + function test_fail_url() { + WebEngine.settings.errorPageEnabled = false + var url = Qt.resolvedUrl("test1.html") + webEngineView.url = url + compare(webEngineView.url, url) + verify(webEngineView.waitForLoadSucceeded()) + compare(webEngineView.url, url) + + webEngineView.url = unavailableUrl + compare(webEngineView.url, unavailableUrl) + verify(webEngineView.waitForLoadFailed()) + // 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. + compare(webEngineView.url, url) + } + + function test_error_page() { + WebEngine.settings.errorPageEnabled = true + webEngineView.url = unavailableUrl + + // Loading of the error page must be successful + verify(webEngineView.waitForLoadFailed()) + + // Start to load unavailableUrl + let loadStart = loadSpy.signalArguments[0][0] + compare(loadStart.status, WebEngineView.LoadStartedStatus) + compare(loadStart.errorDomain, WebEngineView.NoErrorDomain) + compare(loadStart.errorDomain, WebEngineLoadingInfo.NoErrorDomain) + compare(loadStart.url, unavailableUrl) + verify(!loadStart.isErrorPage) + + // Loading of the unavailableUrl must fail + let loadFail = loadSpy.signalArguments[1][0] + compare(loadFail.status, WebEngineView.LoadFailedStatus) + compare(loadFail.errorDomain, WebEngineView.InternalErrorDomain) + compare(loadFail.errorDomain, WebEngineLoadingInfo.InternalErrorDomain) + compare(loadFail.url, unavailableUrl) + verify(loadFail.isErrorPage) + + compare(webEngineView.url, unavailableUrl) + compare(webEngineView.title, unavailableUrl) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_loadHtml.qml b/tests/auto/quick/qmltests/data/tst_loadHtml.qml index ed1de41fd..8f94cd4a2 100644 --- a/tests/auto/quick/qmltests/data/tst_loadHtml.qml +++ b/tests/auto/quick/qmltests/data/tst_loadHtml.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -42,6 +17,7 @@ TestWebEngineView { } TestCase { + id: testCase name: "WebEngineViewLoadHtml" when: windowShown diff --git a/tests/auto/quick/qmltests/data/tst_loadProgress.qml b/tests/auto/quick/qmltests/data/tst_loadProgress.qml index 7bfe1d9e9..2c06a0207 100644 --- a/tests/auto/quick/qmltests/data/tst_loadProgress.qml +++ b/tests/auto/quick/qmltests/data/tst_loadProgress.qml @@ -1,36 +1,11 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine -import Test.Shared 1.0 as Shared +import Test.Shared as Shared TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml index 81a0f0904..c0eb5932b 100644 --- a/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml +++ b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.3 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine Item { width: 300 diff --git a/tests/auto/quick/qmltests/data/tst_loadUrl.qml b/tests/auto/quick/qmltests/data/tst_loadUrl.qml index 872c46641..25a62c878 100644 --- a/tests/auto/quick/qmltests/data/tst_loadUrl.qml +++ b/tests/auto/quick/qmltests/data/tst_loadUrl.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -37,10 +12,10 @@ TestWebEngineView { property var loadRequestArray: [] - onLoadingChanged: { + onLoadingChanged: function(load) { loadRequestArray.push({ - "status": loadRequest.status, - "url": loadRequest.url, + "status": load.status, + "url": load.url, "activeUrl": webEngineView.url }); } @@ -52,6 +27,7 @@ TestWebEngineView { } TestCase { + id: testCase name: "WebEngineViewLoadUrl" when: windowShown @@ -79,8 +55,8 @@ TestWebEngineView { var aboutBlank = "about:blank"; webEngineView.url = aboutBlank; verify(webEngineView.waitForLoadSucceeded()); - compare(loadRequestArray[0].status, WebEngineView.LoadStartedStatus); - compare(loadRequestArray[1].status, WebEngineView.LoadSucceededStatus); + compare(loadRequestArray[0].status, WebEngineLoadingInfo.LoadStartedStatus); + compare(loadRequestArray[1].status, WebEngineLoadingInfo.LoadSucceededStatus); compare(loadRequestArray.length, 2); compare(webEngineView.url, aboutBlank); webEngineView.clear(); @@ -133,6 +109,7 @@ TestWebEngineView { compare(loadRequest.activeUrl, bogusSite); loadRequest = loadRequestArray[1]; compare(loadRequest.status, WebEngineView.LoadFailedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadFailedStatus); compare(loadRequest.activeUrl, url); webEngineView.clear(); @@ -148,10 +125,10 @@ TestWebEngineView { compare(loadRequest.status, WebEngineView.LoadSucceededStatus); compare(loadRequest.activeUrl, redirectUrl); loadRequest = loadRequestArray[2]; - compare(loadRequest.status, WebEngineView.LoadStartedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadStartedStatus); compare(loadRequest.activeUrl, redirectUrl); loadRequest = loadRequestArray[3]; - compare(loadRequest.status, WebEngineView.LoadSucceededStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadSucceededStatus); compare(loadRequest.activeUrl, url); webEngineView.clear(); @@ -173,11 +150,11 @@ TestWebEngineView { tryCompare(loadRequestArray, "length", 2); loadRequest = loadRequestArray[0]; - compare(loadRequest.status, WebEngineView.LoadStartedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadStartedStatus); compare(loadRequest.url, url); compare(loadRequest.activeUrl, lastUrl); loadRequest = loadRequestArray[1]; - compare(loadRequest.status, WebEngineView.LoadSucceededStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadSucceededStatus); compare(loadRequest.url, url); compare(loadRequest.activeUrl, url); webEngineView.clear(); @@ -225,15 +202,16 @@ TestWebEngineView { compare(loadRequest.activeUrl, bogusSite); loadRequest = loadRequestArray[1]; compare(loadRequest.status, WebEngineView.LoadFailedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadFailedStatus); // Since the load did not succeed the active url is the // URL of the previous successful load. compare(loadRequest.activeUrl, aboutBlank); loadRequest = loadRequestArray[2]; - compare(loadRequest.status, WebEngineView.LoadStartedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadStartedStatus); compare(loadRequest.activeUrl, bogusSite); compare(loadRequest.url, "data:text/html;charset=UTF-8,load failed") loadRequest = loadRequestArray[3]; - compare(loadRequest.status, WebEngineView.LoadSucceededStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadSucceededStatus); compare(loadRequest.activeUrl, bogusSite); compare(loadRequest.url, bogusSite) webEngineView.clear(); @@ -285,6 +263,7 @@ TestWebEngineView { compare(loadRequest.activeUrl, stoppedUrl); loadRequest = loadRequestArray[1]; compare(loadRequest.status, WebEngineView.LoadStoppedStatus); + compare(loadRequest.status, WebEngineLoadingInfo.LoadStoppedStatus); compare(loadRequest.url, stoppedUrl); compare(loadRequest.activeUrl, initialUrl); webEngineView.clear(); @@ -298,20 +277,19 @@ TestWebEngineView { compare(loadRequestArray[0].status, WebEngineView.LoadStartedStatus); compare(loadRequestArray[1].status, WebEngineView.LoadSucceededStatus); - // In-page navigation. - webEngineView.url = Qt.resolvedUrl("test4.html#content"); - // In-page navigation doesn't trigger load succeeded, wait for load progress instead. - tryCompare(webEngineView, "loadProgress", 100); - compare(loadRequestArray.length, 3); - compare(loadRequestArray[2].status, WebEngineView.LoadStartedStatus); + // In-page navigation shouldn't trigger load + let anchorUrl = Qt.resolvedUrl("test4.html#anchor"); + let c = webEngineView.getElementCenter('anchor') + mouseClick(webEngineView, c.x, c.y) + tryCompare(webEngineView, 'url', anchorUrl) // Load after in-page navigation. webEngineView.url = Qt.resolvedUrl("test4.html"); verify(webEngineView.waitForLoadSucceeded()); compare(webEngineView.loadProgress, 100); - compare(loadRequestArray.length, 5); - compare(loadRequestArray[3].status, WebEngineView.LoadStartedStatus); - compare(loadRequestArray[4].status, WebEngineView.LoadSucceededStatus); + compare(loadRequestArray.length, 4); + compare(loadRequestArray[2].status, WebEngineView.LoadStartedStatus); + compare(loadRequestArray[3].status, WebEngineView.LoadSucceededStatus); webEngineView.clear(); } diff --git a/tests/auto/quick/qmltests/data/tst_mouseClick.qml b/tests/auto/quick/qmltests/data/tst_mouseClick.qml new file mode 100644 index 000000000..c0c6a6967 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_mouseClick.qml @@ -0,0 +1,108 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" + +TestWebEngineView { + id: webEngineView + width: 200 + height: 200 + + TestInputEvent { + id: testInputEvent + + function __mouseMultiClick(item, x, y, clickCount) { + if (!item) + qtest_fail("No item given to mouseMultiClick", 1); + + if (x === undefined) + x = item.width / 2; + if (y === undefined) + y = item.height / 2; + if (!mouseMultiClick(item, x, y, clickCount)) + qtest_fail("window not shown", 2); + } + + function mouseDoubleClick(item, x, y) { + __mouseMultiClick(item, x, y, 2); + } + + function mouseTripleClick(item, x, y) { + __mouseMultiClick(item, x, y, 3); + } + + function mouseQuadraClick(item, x, y) { + __mouseMultiClick(item, x, y, 4); + } + } + + + TestCase { + id: testCase + name: "WebEngineViewMouseClick" + when: windowShown + + function test_singleClick() { + webEngineView.settings.focusOnNavigationEnabled = false; + webEngineView.loadHtml("<html><body>" + + "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + verify(!getActiveElementId()); + + var center = getElementCenter("input"); + mouseClick(webEngineView, center.x, center.y); + verifyElementHasFocus("input"); + compare(getTextSelection(), ""); + } + + function test_doubleClick() { + webEngineView.settings.focusOnNavigationEnabled = true; + webEngineView.loadHtml("<html><body onload='document.getElementById(\"input\").focus()'>" + + "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + + var center = getElementCenter("input"); + testInputEvent.mouseDoubleClick(webEngineView, center.x, center.y); + verifyElementHasFocus("input"); + tryVerify(function() { return getTextSelection() == "Company" }); + + mouseClick(webEngineView, center.x, center.y); + tryVerify(function() { return getTextSelection() == "" }); + } + + function test_tripleClick() { + webEngineView.settings.focusOnNavigationEnabled = true; + webEngineView.loadHtml("<html><body onload='document.getElementById(\"input\").focus()'>" + + "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + + var center = getElementCenter("input"); + testInputEvent.mouseTripleClick(webEngineView, center.x, center.y); + verifyElementHasFocus("input"); + tryVerify(function() { return getTextSelection() == "The Qt Company" }); + + mouseClick(webEngineView, center.x, center.y); + tryVerify(function() { return getTextSelection() == "" }); + } + + function test_quadraClick() { + webEngineView.settings.focusOnNavigationEnabled = true; + webEngineView.loadHtml("<html><body onload='document.getElementById(\"input\").focus()'>" + + "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + + var center = getElementCenter("input"); + testInputEvent.mouseQuadraClick(webEngineView, center.x, center.y); + verifyElementHasFocus("input"); + tryVerify(function() { return getTextSelection() == "" }); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_mouseMove.qml b/tests/auto/quick/qmltests/data/tst_mouseMove.qml index adfa3941c..5ded24c57 100644 --- a/tests/auto/quick/qmltests/data/tst_mouseMove.qml +++ b/tests/auto/quick/qmltests/data/tst_mouseMove.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.4 +import QtQuick +import QtTest +import QtWebEngine Rectangle { id: root diff --git a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml index 6ed232589..2ea76c387 100644 --- a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml +++ b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -38,7 +13,7 @@ TestWebEngineView { ListView { id: backItemsList anchors.fill: parent - model: webEngineView.navigationHistory.backItems + model: webEngineView.history.backItems currentIndex: count - 1 delegate: Text { @@ -50,7 +25,7 @@ TestWebEngineView { ListView { id: forwardItemsList anchors.fill: parent - model: webEngineView.navigationHistory.forwardItems + model: webEngineView.history.forwardItems currentIndex: 0 delegate: Text { @@ -59,11 +34,23 @@ TestWebEngineView { } } + Item { // simple button-like interface to not depend on controls + id: backButton + enabled: webEngineView.canGoBack + function clicked() { if (enabled) webEngineView.goBack() } + } + + Item { // simple button-like interface to not depend on controls + id: forwardButton + enabled: webEngineView.canGoForward + function clicked() { if (enabled) webEngineView.goForward() } + } + TestCase { - name: "WebEngineViewNavigationHistory" + name: "NavigationHistory" function test_navigationHistory() { - compare(webEngineView.loadProgress, 0) + webEngineView.history.clear() webEngineView.url = Qt.resolvedUrl("test1.html") verify(webEngineView.waitForLoadSucceeded()) @@ -135,12 +122,58 @@ TestWebEngineView { compare(backItemsList.currentItem.text, Qt.resolvedUrl("test1.html")) compare(forwardItemsList.currentItem.text, Qt.resolvedUrl("javascript.html")) - webEngineView.navigationHistory.clear() + webEngineView.history.clear() compare(webEngineView.url, Qt.resolvedUrl("test2.html")) compare(webEngineView.canGoBack, false) compare(webEngineView.canGoForward, false) compare(backItemsList.count, 0) compare(forwardItemsList.count, 0) } + + function test_navigationButtons() { + webEngineView.history.clear() + + const url1 = Qt.resolvedUrl("test1.html") + webEngineView.url = url1 + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, false) + compare(forwardButton.enabled, false) + + const url2 = Qt.resolvedUrl("test2.html") + webEngineView.url = url2 + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, true) + compare(forwardButton.enabled, false) + + const url3 = Qt.resolvedUrl("test3.html") + webEngineView.url = url3 + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, true) + compare(forwardButton.enabled, false) + + backButton.clicked() + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, true) + compare(forwardButton.enabled, true) + compare(webEngineView.url, url2) + + backButton.clicked() + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, false) + compare(forwardButton.enabled, true) + compare(webEngineView.url, url1) + + forwardButton.clicked() + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, true) + compare(forwardButton.enabled, true) + compare(webEngineView.url, url2) + + webEngineView.url = url1 + verify(webEngineView.waitForLoadSucceeded()) + compare(backButton.enabled, true) + compare(forwardButton.enabled, false) + compare(webEngineView.url, url1) + } } } diff --git a/tests/auto/quick/qmltests/data/tst_navigationRequested.qml b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml index 96128574e..31c0cf44e 100644 --- a/tests/auto/quick/qmltests/data/tst_navigationRequested.qml +++ b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -59,26 +34,27 @@ TestWebEngineView { signalName: "navigationRequested" } - onNavigationRequested: { + onNavigationRequested: function(request) { if (request.isMainFrame) { attributes.mainUrl = request.url } else { attributes.iframeUrl = request.url if (shouldIgnoreSubFrameRequests) { - request.action = WebEngineView.IgnoreRequest + request.reject() } } - if (request.navigationType === WebEngineView.LinkClickedNavigation) { + if (request.navigationType === WebEngineNavigationRequest.LinkClickedNavigation) { attributes.linkClickedNavigationRequested = true if (shouldIgnoreLinkClicks) { - request.action = WebEngineView.IgnoreRequest + request.reject() attributes.linkClickedNavigationIgnored = true } } } TestCase { + id: testCase name: "WebEngineViewNavigationRequested" when: windowShown @@ -93,19 +69,17 @@ TestWebEngineView { // Test if we get notified about main frame and iframe loads compare(navigationSpy.count, 0) webEngineView.url = Qt.resolvedUrl("test-iframe.html") - navigationSpy.wait() + verify(webEngineView.waitForLoadSucceeded()) compare(attributes.mainUrl, Qt.resolvedUrl("test-iframe.html")) - navigationSpy.wait() compare(attributes.iframeUrl, Qt.resolvedUrl("test1.html")) compare(navigationSpy.count, 2) - verify(webEngineView.waitForLoadSucceeded()) // Test if we get notified about clicked links mouseClick(webEngineView, 100, 100) - tryCompare(navigationSpy, "count", 3) + verify(webEngineView.waitForLoadSucceeded()) compare(attributes.mainUrl, Qt.resolvedUrl("test1.html")) verify(attributes.linkClickedNavigationRequested) - verify(webEngineView.waitForLoadSucceeded()) + compare(navigationSpy.count, 3) } function test_ignoreLinkClickedRequest() { @@ -116,26 +90,28 @@ TestWebEngineView { shouldIgnoreLinkClicks = true mouseClick(webEngineView, 100, 100) - tryCompare(navigationSpy, "count", 3) - compare(attributes.mainUrl, Qt.resolvedUrl("test1.html")) - verify(attributes.linkClickedNavigationRequested) - verify(attributes.linkClickedNavigationIgnored) // We ignored the main frame request, so we should // get notified that the load has been stopped. verify(webEngineView.waitForLoadStopped()) verify(!webEngineView.loading) + + compare(navigationSpy.count, 3) + compare(attributes.mainUrl, Qt.resolvedUrl("test1.html")) + verify(attributes.linkClickedNavigationRequested) + verify(attributes.linkClickedNavigationIgnored) } function test_ignoreSubFrameRequest() { // Test if we can ignore sub frame requests shouldIgnoreSubFrameRequests = true webEngineView.url = Qt.resolvedUrl("test-iframe.html") - tryCompare(navigationSpy, "count", 2) - compare(attributes.mainUrl, Qt.resolvedUrl("test-iframe.html")) - compare(attributes.iframeUrl, Qt.resolvedUrl("test1.html")) // We ignored the sub frame request, so // the main frame load should still succeed. verify(webEngineView.waitForLoadSucceeded()) + + compare(navigationSpy.count, 2) + compare(attributes.mainUrl, Qt.resolvedUrl("test-iframe.html")) + compare(attributes.iframeUrl, Qt.resolvedUrl("test1.html")) } } } diff --git a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml index 80389e9f8..68350d107 100644 --- a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml +++ b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.5 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -38,14 +13,21 @@ TestWebEngineView { property var newViewRequest: null property var dialog: null property string viewType: "" + property var loadRequestArray: [] + + onLoadingChanged: function(load) { + loadRequestArray.push({ + "status": load.status, + }); + } SignalSpy { id: newViewRequestedSpy target: webEngineView - signalName: "newViewRequested" + signalName: "newWindowRequested" } - onNewViewRequested: { + onNewWindowRequested: function(request) { newViewRequest = { "destination": request.destination, "userInitiated": request.userInitiated, @@ -53,7 +35,7 @@ TestWebEngineView { }; dialog = Qt.createQmlObject( - "import QtQuick.Window 2.0\n" + + "import QtQuick.Window\n" + "Window {\n" + " width: 100; height: 100\n" + " visible: true; flags: Qt.Dialog\n" + @@ -70,8 +52,8 @@ TestWebEngineView { } TestCase { - id: test - name: "NewViewRequest" + id: testCase + name: "NewWindowRequest" when: windowShown function init() { @@ -81,6 +63,7 @@ TestWebEngineView { newViewRequestedSpy.clear(); newViewRequest = null; viewType = ""; + loadRequestArray = []; } function cleanup() { @@ -88,7 +71,7 @@ TestWebEngineView { dialog.destroy(); } - function test_loadNewViewRequest_data() { + function test_loadNewWindowRequest_data() { return [ { tag: "dialog", viewType: "dialog" }, { tag: "invalid", viewType: "null" }, @@ -97,7 +80,7 @@ TestWebEngineView { ]; } - function test_loadNewViewRequest(row) { + function test_loadNewWindowRequest(row) { viewType = row.viewType; var url = 'data:text/html,%3Chtml%3E%3Cbody%3ETest+Page%3C%2Fbody%3E%3C%2Fhtml%3E'; @@ -110,16 +93,15 @@ TestWebEngineView { verify(webEngineView.waitForLoadSucceeded()); tryCompare(newViewRequestedSpy, "count", 1); - compare(newViewRequest.destination, WebEngineView.NewViewInTab); + compare(newViewRequest.destination, WebEngineNewWindowRequest.InNewTab); verify(!newViewRequest.userInitiated); if (viewType === "dialog") { - verify(dialog.webEngineView.waitForLoadSucceeded()); - compare(dialog.webEngineView.url, ""); + tryVerify(dialog.webEngineView.loadSucceeded) + compare(dialog.webEngineView.url, Qt.url("about:blank")); dialog.destroy(); } - // https://chromium-review.googlesource.com/c/chromium/src/+/1300395 - compare(newViewRequest.requestedUrl, 'about:blank#blocked'); + compare(newViewRequest.requestedUrl, 'about:blank'); newViewRequestedSpy.clear(); // Open a page in a new dialog @@ -131,11 +113,11 @@ TestWebEngineView { verify(webEngineView.waitForLoadSucceeded()); tryCompare(newViewRequestedSpy, "count", 1); - compare(newViewRequest.destination, WebEngineView.NewViewInDialog); + compare(newViewRequest.destination, WebEngineNewWindowRequest.InNewDialog); compare(newViewRequest.requestedUrl, url); verify(!newViewRequest.userInitiated); if (viewType === "dialog") { - verify(dialog.webEngineView.waitForLoadSucceeded()); + tryVerify(dialog.webEngineView.loadSucceeded) dialog.destroy(); } newViewRequestedSpy.clear(); @@ -150,19 +132,36 @@ TestWebEngineView { " <button id='popupButton' onclick='popup()'>Pop Up!</button>" + "</body></html>"); verify(webEngineView.waitForLoadSucceeded()); - verifyElementHasFocus("popupButton"); + webEngineView.verifyElementHasFocus("popupButton"); keyPress(Qt.Key_Enter); tryCompare(newViewRequestedSpy, "count", 1); compare(newViewRequest.requestedUrl, url); - compare(newViewRequest.destination, WebEngineView.NewViewInDialog); + compare(newViewRequest.destination, WebEngineNewWindowRequest.InNewDialog); verify(newViewRequest.userInitiated); if (viewType === "dialog") { - verify(dialog.webEngineView.waitForLoadSucceeded()); + tryVerify(dialog.webEngineView.loadSucceeded) dialog.destroy(); } newViewRequestedSpy.clear(); } + + loadRequestArray = []; + compare(loadRequestArray.length, 0); + webEngineView.url = Qt.resolvedUrl("test2.html"); + verify(webEngineView.waitForLoadSucceeded()); + var center = webEngineView.getElementCenter("link"); + mouseClick(webEngineView, center.x, center.y, Qt.LeftButton, Qt.ControlModifier); + tryCompare(newViewRequestedSpy, "count", 1); + compare(newViewRequest.requestedUrl, Qt.resolvedUrl("test1.html")); + compare(newViewRequest.destination, WebEngineNewWindowRequest.InNewBackgroundTab); + verify(newViewRequest.userInitiated); + if (viewType === "" || viewType === "null") { + compare(loadRequestArray[0].status, WebEngineView.LoadStartedStatus); + compare(loadRequestArray[1].status, WebEngineView.LoadSucceededStatus); + compare(loadRequestArray.length, 2); + } + newViewRequestedSpy.clear(); } } } diff --git a/tests/auto/quick/qmltests/data/tst_notification.qml b/tests/auto/quick/qmltests/data/tst_notification.qml index 773bf4a8e..5d55e1201 100644 --- a/tests/auto/quick/qmltests/data/tst_notification.qml +++ b/tests/auto/quick/qmltests/data/tst_notification.qml @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtTest 1.0 -import QtWebEngine 1.9 +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.Shared as Shared TestWebEngineView { id: view @@ -47,7 +23,7 @@ TestWebEngineView { signalName: 'featurePermissionRequested' } - onFeaturePermissionRequested: { + onFeaturePermissionRequested: function(securityOrigin, feature) { if (feature === WebEngineView.Notifications) { view.permissionRequested = true view.securityOrigin = securityOrigin @@ -60,7 +36,8 @@ TestWebEngineView { when: windowShown function resolverUrl(html) { - return Qt.resolvedUrl('../../../shared/data/' + html) + console.log(Shared.HttpServer.sharedDataDir()) + return Qt.resolvedUrl(Shared.HttpServer.sharedDataDir() + "/" + html) } function init() { diff --git a/tests/auto/quick/qmltests/data/tst_profile.qml b/tests/auto/quick/qmltests/data/tst_profile.qml deleted file mode 100644 index ee7fa4e99..000000000 --- a/tests/auto/quick/qmltests/data/tst_profile.qml +++ /dev/null @@ -1,66 +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$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.9 - -TestWebEngineView { - id: webEngineView - width: 400 - height: 300 - - - WebEngineProfile { - id: profile1 - } - WebEngineProfile { - id: profile2 - } - property bool profile1UsedForGlobalCertificateVerification: profile1.useForGlobalCertificateVerification - - TestCase { - name: "WebEngineProfile" - - function test_useForGlobalCertificateVerification() { - verify(!profile1.useForGlobalCertificateVerification); - verify(!profile2.useForGlobalCertificateVerification); - verify(!webEngineView.profile1UsedForGlobalCertificateVerification); - - profile1.useForGlobalCertificateVerification = true; - verify(profile1.useForGlobalCertificateVerification); - verify(!profile2.useForGlobalCertificateVerification); - verify(webEngineView.profile1UsedForGlobalCertificateVerification); - - profile2.useForGlobalCertificateVerification = true; - verify(!webEngineView.profile1UsedForGlobalCertificateVerification); - verify(!profile1.useForGlobalCertificateVerification); - verify(profile2.useForGlobalCertificateVerification); - } - } -} diff --git a/tests/auto/quick/qmltests/data/tst_properties.qml b/tests/auto/quick/qmltests/data/tst_properties.qml index 89f8af9b8..13d40ed11 100644 --- a/tests/auto/quick/qmltests/data/tst_properties.qml +++ b/tests/auto/quick/qmltests/data/tst_properties.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml index beeebc049..f16cd9c41 100644 --- a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml +++ b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -59,8 +34,7 @@ TestWebEngineView { compare(result, testTitle2); callbackCalled = true; }); - wait(100); - verify(callbackCalled); + tryVerify(function() { return callbackCalled; }); } } } diff --git a/tests/auto/quick/qmltests/data/tst_save.qml b/tests/auto/quick/qmltests/data/tst_save.qml new file mode 100644 index 000000000..3289dbd8b --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_save.qml @@ -0,0 +1,185 @@ +import QtQuick +import QtTest +import QtWebEngine +import Test.util + +TestWebEngineView { + id: webEngineView + width: 200 + height: 200 + profile: testSaveProfile + + property url downloadUrl: "" + property int totalBytes: 0 + property int receivedBytes: 0 + property string downloadDir: "" + property string downloadFileName: "" + property bool isSavePageDownload: false + property var downloadState: [] + property int savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat; + property bool autoCancel: false + + TempDir { + id: tempDir + } + + SignalSpy { + id: downLoadRequestedSpy + target: testSaveProfile + signalName: "downloadRequested" + } + + SignalSpy { + id: downloadFinishedSpy + target: testSaveProfile + signalName: "downloadFinished" + } + + WebEngineProfile { + id: testSaveProfile + + onDownloadRequested: function(download) { + downloadState.push(download.state) + downloadUrl = download.url + savePageFormat = download.savePageFormat + downloadDir = download.downloadDirectory; + downloadFileName = download.downloadFileName + isSavePageDownload = download.isSavePageDownload + + if (autoCancel) + download.cancel() + } + onDownloadFinished: function(download) { + receivedBytes = download.receivedBytes + totalBytes = download.totalBytes + downloadState.push(download.state) + } + } + + TestCase { + name: "WebEngineViewSave" + + function verifyData() { + var isDataValid = false + webEngineView.runJavaScript("(function() {" + + "var title = document.title.toString();" + + "var body = document.body.innerText;" + + " return title === \"Test page 1\" && body.includes(\"Hello.\")" + + "})();", function(result) { + isDataValid = result; + }); + tryVerify(function() { return isDataValid }); + return isDataValid; + } + + function init() { + downLoadRequestedSpy.clear() + downloadFinishedSpy.clear() + totalBytes = 0 + receivedBytes = 0 + downloadDir = "" + downloadFileName = "" + isSavePageDownload = false + downloadState = [] + downloadUrl = "" + autoCancel = false + } + + function test_savePage_data() { + return [ + { tag: "SingleHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.SingleHtmlSaveFormat }, + { tag: "CompleteHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.CompleteHtmlSaveFormat }, + { tag: "MimeHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat }, + ]; + } + + function test_savePage(row) { + var saveFormat = row.savePageFormat + + var fileDir = tempDir.path() + var fileName = "saved_page.html" + var filePath = fileDir + "/"+ fileName + + // load data to view + webEngineView.url = Qt.resolvedUrl("test1.html") + verify(webEngineView.waitForLoadSucceeded()) + verify(verifyData()) + + webEngineView.save(filePath, saveFormat) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(savePageFormat, saveFormat) + compare(downloadDir, fileDir) + compare(downloadFileName, fileName) + compare(isSavePageDownload, true) + compare(downloadState[0], WebEngineDownloadRequest.DownloadInProgress) + downloadFinishedSpy.wait() + compare(downloadFinishedSpy.count, 1) + compare(totalBytes, receivedBytes) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCompleted) + + // load some other data + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + // load save file to view + webEngineView.url = Qt.resolvedUrl(filePath) + verify(webEngineView.waitForLoadSucceeded()) + verify(verifyData()) + } + + function test_saveImage_data() { + return [ + { tag: "Auto accept", autoCancel: false }, + { tag: "Cancel", autoCancel: true }, + ]; + } + + function test_saveImage(row) { + autoCancel = row.autoCancel + + var fileDir = tempDir.path() + var fileName = "favicon.png" + var filePath = fileDir + "/"+ fileName + + // Load an image + webEngineView.url = Qt.resolvedUrl("icons/favicon.png") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.save(filePath) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(downloadDir, fileDir) + compare(downloadFileName, fileName) + compare(isSavePageDownload, true) + compare(downloadState[0], WebEngineDownloadRequest.DownloadInProgress) + downloadFinishedSpy.wait() + compare(downloadFinishedSpy.count, 1) + if (autoCancel) { + compare(receivedBytes, 0) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCancelled) + } else { + compare(totalBytes, receivedBytes) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCompleted) + } + } + + function test_saveWebAction() { + // Load an image + webEngineView.url = Qt.resolvedUrl("icons/favicon.png") + verify(webEngineView.waitForLoadSucceeded()) + + // Saving without specifying path shouldn't be auto accepted + webEngineView.triggerWebAction(WebEngineView.SavePage) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(isSavePageDownload, true) + // The initial download request starts from DownloadRequested state, + // which means it wasn't automatically accepted. + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml index 24b352dde..cc7d15e4c 100644 --- a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml +++ b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml @@ -1,35 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.2 -import QtQuick.Window 2.0 -import QtTest 1.0 -import QtWebEngine 1.3 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -61,7 +35,7 @@ TestWebEngineView { tryCompare(scrollPositionSpy, "count", 1); compare(webEngineView.scrollPosition.x, 0); - compare(webEngineView.scrollPosition.y, 600 * Screen.devicePixelRatio); + compare(webEngineView.scrollPosition.y, 600); } function test_scrollPositionAfterReload() { @@ -74,13 +48,13 @@ TestWebEngineView { // Wait for proper scroll position change otherwise we cannot expect // the new y position after reload. tryCompare(webEngineView.scrollPosition, "x", 0); - tryCompare(webEngineView.scrollPosition, "y", 600 * Screen.devicePixelRatio); + tryCompare(webEngineView.scrollPosition, "y", 600); webEngineView.reload(); verify(webEngineView.waitForLoadSucceeded()); tryCompare(webEngineView.scrollPosition, "x", 0); - tryCompare(webEngineView.scrollPosition, "y", 600 * Screen.devicePixelRatio); + tryCompare(webEngineView.scrollPosition, "y", 600); } } } diff --git a/tests/auto/quick/qmltests/data/tst_settings.qml b/tests/auto/quick/qmltests/data/tst_settings.qml index 2ff4f9c3c..f47674aa7 100644 --- a/tests/auto/quick/qmltests/data/tst_settings.qml +++ b/tests/auto/quick/qmltests/data/tst_settings.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -36,6 +11,7 @@ TestWebEngineView { height: 300 TestCase { + id: testCase name: "WebEngineViewSettings" function test_javascriptEnabled() { @@ -75,7 +51,7 @@ TestWebEngineView { } function test_settingsAffectCurrentViewOnly() { - var webEngineView2 = Qt.createQmlObject('TestWebEngineView {width: 400; height: 300;}', webEngineView); + var webEngineView2 = Qt.createQmlObject('TestWebEngineView {width: 400; height: 300;}', testCase); webEngineView.settings.javascriptEnabled = true; webEngineView2.settings.javascriptEnabled = true; @@ -102,6 +78,68 @@ TestWebEngineView { webEngineView2.destroy(); } + + function test_disableReadingFromCanvas_data() { + return [ + { tag: 'disabled', disableReadingFromCanvas: false, result: true }, + { tag: 'enabled', disableReadingFromCanvas: true, result: false }, + ] + } + + function test_disableReadingFromCanvas(data) { + webEngineView.settings.readingFromCanvasEnabled = !data.disableReadingFromCanvas; + webEngineView.loadHtml("<html><body>" + + "<canvas id='myCanvas' width='200' height='40' style='border:1px solid #000000;'></canvas>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + verify(webEngineView.settings.readingFromCanvasEnabled === !data.disableReadingFromCanvas ) + + var jsCode = "(function(){" + + " var canvas = document.getElementById(\"myCanvas\");" + + " var ctx = canvas.getContext(\"2d\");" + + " ctx.fillStyle = \"rgb(255,0,255)\";" + + " ctx.fillRect(0, 0, 200, 40);" + + " try {" + + " src = canvas.toDataURL();" + + " }" + + " catch(err) {" + + " src = \"\";" + + " }" + + " return src.length ? true : false;" + + "})();"; + + var isDataRead = false; + runJavaScript(jsCode, function(result) { + isDataRead = result + }); + tryVerify(function() { return isDataRead === data.result }); + } + + function test_forceDarkMode() { + // based on: https://developer.chrome.com/blog/auto-dark-theme/#detecting-auto-dark-theme + webEngineView.loadHtml("<html><body>" + + "<div id=\"detection\", style=\"display: none; background-color: canvas; color-scheme: light\"</div>" + + "</body></html>"); + const script = "(() => {" + + " const detectionDiv = document.querySelector('#detection');" + + " return getComputedStyle(detectionDiv).backgroundColor != 'rgb(255, 255, 255)';" + + "})()"; + verify(webEngineView.waitForLoadSucceeded()); + + var isAutoDark = true; + runJavaScript(script, result => isAutoDark = result); + tryVerify(() => {return !isAutoDark}); + + webEngineView.settings.forceDarkMode = true; + verify(webEngineView.settings.forceDarkMode == true) + + isAutoDark = false; + // the page is not updated immediately + tryVerify(function() { + runJavaScript(script, result => isAutoDark = result); + return isAutoDark; + }); + } } } diff --git a/tests/auto/quick/qmltests/data/tst_titleChanged.qml b/tests/auto/quick/qmltests/data/tst_titleChanged.qml index 7dda5ce33..66a7c115f 100644 --- a/tests/auto/quick/qmltests/data/tst_titleChanged.qml +++ b/tests/auto/quick/qmltests/data/tst_titleChanged.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml index 69aa76b77..76363fa71 100644 --- a/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml +++ b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 +import QtQuick +import QtTest +import QtWebEngine Item { id: parentItem @@ -37,8 +12,12 @@ Item { property var pressEvents: [] property var releaseEvents: [] - Keys.onPressed: pressEvents.push(event.key) - Keys.onReleased: releaseEvents.push(event.key) + Keys.onPressed: function(event) { + pressEvents.push(event.key) + } + Keys.onReleased: function(event) { + releaseEvents.push(event.key) + } TestWebEngineView { id: webEngineView @@ -46,6 +25,7 @@ Item { focus: true } TestCase { + id: testCase name: "WebEngineViewUnhandledKeyEventPropagation" when: false diff --git a/tests/auto/quick/qmltests/data/tst_userScriptCollection.qml b/tests/auto/quick/qmltests/data/tst_userScriptCollection.qml new file mode 100644 index 000000000..94c993771 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_userScriptCollection.qml @@ -0,0 +1,127 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +Item { + + WebEngineProfile { id: testProfile } + + TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + } + + TestCase { + name: "UserScriptCollection" + + function cleanup() { + webEngineView.url = "" + webEngineView.userScripts.collection = [] + compare(webEngineView.userScripts.collection.length, 0) + } + + function test_collection() { + let scriptFoo = { name: "Foo", + sourceUrl: Qt.resolvedUrl("foo.js"), + injectionPoint: WebEngineScript.DocumentReady + } + let scriptBar = WebEngine.script() + + scriptBar.name = "Bar" + scriptBar.sourceUrl = Qt.resolvedUrl("bar.js") + scriptBar.injectionPoint = WebEngineScript.DocumentReady + + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.userScripts.collection = [ scriptFoo, scriptBar ] + compare(webEngineView.userScripts.collection.length, 2) + compare(webEngineView.userScripts.collection[0].name, scriptFoo.name) + compare(webEngineView.userScripts.collection[0].sourceUrl, scriptFoo.sourceUrl) + compare(webEngineView.userScripts.collection[1].name, scriptBar.name) + compare(webEngineView.userScripts.collection[1].sourceUrl, scriptBar.sourceUrl) + webEngineView.userScripts.collection = [] + compare(webEngineView.userScripts.collection.length, 0) + } + + function test_insert() { + let scriptFoo = WebEngine.script() + scriptFoo.name = "Foo" + scriptFoo.sourceUrl = Qt.resolvedUrl("foo.js") + scriptFoo.injectionPoint = WebEngineScript.DocumentReady + let scriptBar = WebEngine.script() + scriptBar.name = "Bar" + scriptBar.sourceUrl = Qt.resolvedUrl("bar.js") + scriptBar.injectionPoint = WebEngineScript.DocumentReady + + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.userScripts.insert(scriptFoo) + webEngineView.userScripts.insert(scriptBar) + compare(webEngineView.userScripts.collection.length, 2) + compare(webEngineView.userScripts.collection[0].name, scriptFoo.name) + compare(webEngineView.userScripts.collection[1].name, scriptBar.name) + webEngineView.userScripts.collection = [] + compare(webEngineView.userScripts.collection.length, 0) + + var list = [ scriptFoo , scriptBar] + webEngineView.userScripts.insert(list) + compare(webEngineView.userScripts.collection.length, 2) + compare(webEngineView.userScripts.collection[0].name, scriptFoo.name) + compare(webEngineView.userScripts.collection[1].name, scriptBar.name) + } + + function test_find() { + let scriptA = WebEngine.script() + scriptA.name = "A" + scriptA.sourceUrl = Qt.resolvedUrl("A.js") + let scriptB = WebEngine.script() + scriptB.name = "A" + scriptB.sourceUrl = Qt.resolvedUrl("B.js") + let scriptC = WebEngine.script() + scriptC.name = "C" + scriptC.sourceUrl = Qt.resolvedUrl("C.js") + + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.userScripts.collection = [ scriptA, scriptB, scriptC ]; + compare(webEngineView.userScripts.collection.length, 3) + let scriptsA = webEngineView.userScripts.find("A") + let scriptsB = webEngineView.userScripts.find("B") + let scriptsC = webEngineView.userScripts.find("C") + compare(scriptsA.length, 2) + compare(scriptsB.length, 0) + compare(scriptsC.length, 1) + compare(scriptsA[0].name, scriptA.name) + compare(scriptsA[0].sourceUrl, scriptA.sourceUrl) + compare(scriptsA[1].name, scriptB.name) + compare(scriptsA[1].sourceUrl, scriptB.sourceUrl) + compare(scriptsC[0].name, scriptC.name) + compare(scriptsC[0].sourceUrl, scriptC.sourceUrl) + } + + function test_contains() { + let scriptFoo = WebEngine.script() + scriptFoo.name = "Foo" + let scriptBar = WebEngine.script() + scriptBar.name = "Bar" + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.userScripts.collection = [ scriptFoo ] + compare(webEngineView.userScripts.collection.length, 1) + verify(webEngineView.userScripts.contains(scriptFoo)) + verify(!webEngineView.userScripts.contains(scriptBar)) + } + + function test_clear() { + let scriptFoo = WebEngine.script() + scriptFoo.name = "Foo" + let scriptBar = WebEngine.script() + scriptBar.name = "Bar" + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.userScripts.collection = [ scriptFoo ]; + compare(webEngineView.userScripts.collection.length, 1) + webEngineView.userScripts.clear() + compare(webEngineView.userScripts.collection.length, 0) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_userScripts.qml b/tests/auto/quick/qmltests/data/tst_userScripts.qml index f4fcc30ab..30704f47b 100644 --- a/tests/auto/quick/qmltests/data/tst_userScripts.qml +++ b/tests/auto/quick/qmltests/data/tst_userScripts.qml @@ -1,64 +1,42 @@ -/**************************************************************************** -** -** 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.2 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine Item { - WebEngineScript { - id: changeDocumentTitleScript - sourceUrl: Qt.resolvedUrl("change-document-title.js") - injectionPoint: WebEngineScript.DocumentReady + + function changeDocumentTitleScript() { + return { name: "changeDocumentTitleScript", + sourceUrl: Qt.resolvedUrl("change-document-title.js"), + injectionPoint: WebEngineScript.DocumentReady } } - WebEngineScript { - id: appendDocumentTitleScript - sourceUrl: Qt.resolvedUrl("append-document-title.js") - injectionPoint: WebEngineScript.DocumentReady + function appendDocumentTitleScript() { + return { sourceUrl: Qt.resolvedUrl("append-document-title.js"), + injectionPoint: WebEngineScript.DocumentReady } } - WebEngineScript { - id: bigUserScript - sourceUrl: Qt.resolvedUrl("big-user-script.js") - injectionPoint: WebEngineScript.DocumentReady + function bigUserScript() { + return { sourceUrl: Qt.resolvedUrl("big-user-script.js"), + injectionPoint: WebEngineScript.DocumentReady } } - WebEngineScript { - id: scriptWithMetadata - sourceUrl: Qt.resolvedUrl("script-with-metadata.js") + function scriptWithMetadata() { + var script = WebEngine.script() + script.sourceUrl = Qt.resolvedUrl("script-with-metadata.js") + return script } - WebEngineScript { - id: scriptWithBadMatchMetadata - sourceUrl: Qt.resolvedUrl("script-with-bad-match-metadata.js") + function scriptWithBadMatchMetadata() { + var script = WebEngine.script() + script.sourceUrl = Qt.resolvedUrl("script-with-bad-match-metadata.js") + return script } + WebEngineProfile { id: testProfile } + TestWebEngineView { id: webEngineView width: 400 @@ -76,24 +54,40 @@ Item { width: 400 height: 300 - onNavigationRequested: { + onNavigationRequested: function(request) { var urlString = request.url.toString(); if (urlString.indexOf("test1.html") !== -1) - userScripts = [ changeDocumentTitleScript ]; + userScripts.collection = [ changeDocumentTitleScript() ]; else if (urlString.indexOf("test2.html") !== -1) - userScripts = [ appendDocumentTitleScript ]; + userScripts.collection = [ appendDocumentTitleScript() ]; else - userScripts = []; + userScripts.collection = []; } } TestCase { - name: "WebEngineViewUserScripts" + name: "UserScripts" - function init() { + function cleanup() { webEngineView.url = ""; - webEngineView.userScripts = []; - webEngineView.profile.userScripts = []; + webEngineView.userScripts.collection = []; + compare(webEngineView.userScripts.collection.length, 0) + webEngineView.profile.userScripts.collection = []; + compare(webEngineView.profile.userScripts.collection.length, 0) + } + + function test_profileScripts() { + // assusme it is the same type as in View + let t1 = String(testProfile.userScripts), t2 = String(webEngineView.userScripts) + compare(t1.substr(0, t1.indexOf('(')), t2.substr(0, t2.indexOf('('))) + + // ... and just test basic things like access + compare(testProfile.userScripts.collection, []) + let script = changeDocumentTitleScript() + testProfile.userScripts.collection = [ script ] + + compare(testProfile.userScripts.collection.length, 1) + compare(testProfile.userScripts.collection[0].name, script.name) } function test_oneScript() { @@ -101,7 +95,10 @@ Item { webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "Test page 1"); - webEngineView.userScripts = [ changeDocumentTitleScript ]; + let script = changeDocumentTitleScript() + webEngineView.userScripts.collection = [ script ] + compare(webEngineView.userScripts.collection.length, 1) + compare(webEngineView.userScripts.collection[0].name, script.name) compare(webEngineView.title, "Test page 1"); webEngineView.reload(); @@ -112,7 +109,8 @@ Item { webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "New title"); - webEngineView.userScripts = []; + webEngineView.userScripts.collection = []; + compare(webEngineView.userScripts.collection.length, 0) compare(webEngineView.title, "New title"); webEngineView.reload(); @@ -124,23 +122,28 @@ Item { webEngineView.url = Qt.resolvedUrl("test1.html"); webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "Test page 1"); - - webEngineView.userScripts = [ changeDocumentTitleScript, appendDocumentTitleScript ]; + var script1 = changeDocumentTitleScript(); + var script2 = appendDocumentTitleScript(); + script2.injectionPoint = WebEngineScript.Deferred; + webEngineView.userScripts.collection = [ script1, script2 ]; + compare(webEngineView.userScripts.collection.length, 2) // Make sure the scripts are loaded in order. - appendDocumentTitleScript.injectionPoint = WebEngineScript.Deferred webEngineView.reload(); webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "New title with appendix"); - appendDocumentTitleScript.injectionPoint = WebEngineScript.DocumentReady - changeDocumentTitleScript.injectionPoint = WebEngineScript.Deferred + script2.injectionPoint = WebEngineScript.DocumentReady + script1.injectionPoint = WebEngineScript.Deferred + webEngineView.userScripts.collection = [ script1, script2 ]; + compare(webEngineView.userScripts.collection.length, 2) webEngineView.reload(); webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "New title"); // Make sure we can remove scripts from the preload list. - webEngineView.userScripts = [ appendDocumentTitleScript ]; + webEngineView.userScripts.collection = [ script2 ]; + compare(webEngineView.userScripts.collection.length, 1) webEngineView.reload(); webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "Test page 1 with appendix"); @@ -163,17 +166,21 @@ Item { } function test_bigScript() { - webEngineView.userScripts = [ bigUserScript ]; + webEngineView.userScripts.collection = [ bigUserScript() ]; + compare(webEngineView.userScripts.collection.length, 1) webEngineView.url = Qt.resolvedUrl("test1.html"); webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView , "title", "Big user script changed title"); } function test_parseMetadataHeader() { - compare(scriptWithMetadata.name, "Test script"); - compare(scriptWithMetadata.injectionPoint, WebEngineScript.DocumentReady); + var script = scriptWithMetadata() + compare(script.name, "Test script"); + compare(script.injectionPoint, WebEngineScript.DocumentReady); - webEngineView.userScripts = [ scriptWithMetadata ]; + webEngineView.userScripts.collection = [ script ]; + compare(webEngineView.userScripts.collection.length, 1) + compare(webEngineView.userScripts.collection[0].name, script.name) // @include *data/test*.html webEngineView.url = Qt.resolvedUrl("test1.html"); @@ -197,10 +204,12 @@ Item { } function test_dontInjectBadUrlPatternsEverywhere() { - compare(scriptWithBadMatchMetadata.name, "Test bad match script"); - compare(scriptWithBadMatchMetadata.injectionPoint, WebEngineScript.DocumentReady); + var script = scriptWithBadMatchMetadata(); + compare(script.name, "Test bad match script"); + compare(script.injectionPoint, WebEngineScript.DocumentReady); - webEngineView.userScripts = [ scriptWithBadMatchMetadata ]; + webEngineView.userScripts.collection = [ script ]; + compare(webEngineView.userScripts.collection.length, 1) // @match some:junk webEngineView.url = Qt.resolvedUrl("test2.html"); @@ -209,7 +218,10 @@ Item { } function test_profileWideScript() { - webEngineView.profile.userScripts = [ changeDocumentTitleScript ]; + let script = changeDocumentTitleScript() + webEngineView.profile.userScripts.collection = [ script ]; + compare(webEngineView.profile.userScripts.collection.length, 1) + compare(webEngineView.profile.userScripts.collection[0].name, script.name) webEngineView.url = Qt.resolvedUrl("test1.html"); webEngineView.waitForLoadSucceeded(); diff --git a/tests/auto/quick/qmltests/data/tst_viewSource.qml b/tests/auto/quick/qmltests/data/tst_viewSource.qml index 4966a052a..d4449f7de 100644 --- a/tests/auto/quick/qmltests/data/tst_viewSource.qml +++ b/tests/auto/quick/qmltests/data/tst_viewSource.qml @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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 +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine TestWebEngineView { id: webEngineView @@ -38,9 +13,15 @@ TestWebEngineView { property var viewRequest: null SignalSpy { + id: loadSpy + target: webEngineView + signalName: 'loadingChanged' + } + + SignalSpy { id: newViewRequestedSpy target: webEngineView - signalName: "newViewRequested" + signalName: "newWindowRequested" } SignalSpy { @@ -49,13 +30,13 @@ TestWebEngineView { signalName: "titleChanged" } - onNewViewRequested: { + onNewWindowRequested: function(request) { viewRequest = { "destination": request.destination, "userInitiated": request.userInitiated }; - request.openIn(webEngineView); + webEngineView.acceptAsNewWindow(request); } TestCase { @@ -68,6 +49,7 @@ TestWebEngineView { tryCompare(webEngineView, "loadStatus", WebEngineView.LoadSucceededStatus); webEngineView.loadStatus = null; + loadSpy.clear(); newViewRequestedSpy.clear(); titleChangedSpy.clear(); viewRequest = null; @@ -86,7 +68,7 @@ TestWebEngineView { // The first titleChanged signal is emitted by adoptWebContents() tryVerify(function() { return titleChangedSpy.count >= 2; }); - compare(viewRequest.destination, WebEngineView.NewViewInTab); + compare(viewRequest.destination, WebEngineNewWindowRequest.InNewTab); verify(viewRequest.userInitiated); verify(!webEngineView.action(WebEngineView.ViewSource).enabled); @@ -94,36 +76,6 @@ TestWebEngineView { compare(webEngineView.url, "view-source:" + Qt.resolvedUrl("test1.html")); } - function test_viewSourceURL_data() { - var testLocalUrl = "view-source:" + Qt.resolvedUrl("test1.html"); - var testLocalUrlWithoutScheme = "view-source:" + Qt.resolvedUrl("test1.html").substring(7); - - return [ - { tag: "view-source:", userInputUrl: "view-source:", loadSucceed: true, url: "view-source:", title: "view-source:" }, - { tag: "view-source:about:blank", userInputUrl: "view-source:about:blank", loadSucceed: true, url: "view-source:about:blank", title: "view-source:about:blank" }, - { tag: testLocalUrl, userInputUrl: testLocalUrl, loadSucceed: true, url: testLocalUrl, title: "test1.html" }, - { tag: testLocalUrlWithoutScheme, userInputUrl: testLocalUrlWithoutScheme, loadSucceed: true, url: testLocalUrl, title: "test1.html" }, - { tag: "view-source:http://non.existent", userInputUrl: "view-source:http://non.existent", loadSucceed: false, url: "http://non.existent/", title: "non.existent" }, - { tag: "view-source:non.existent", userInputUrl: "view-source:non.existent", loadSucceed: false, url: "http://non.existent/", title: "non.existent" }, - ]; - } - - function test_viewSourceURL(row) { - WebEngine.settings.errorPageEnabled = true - webEngineView.url = row.userInputUrl; - - if (row.loadSucceed) { - tryCompare(webEngineView, "loadStatus", WebEngineView.LoadSucceededStatus); - } else { - tryCompare(webEngineView, "loadStatus", WebEngineView.LoadFailedStatus, 15000); - } - tryVerify(function() { return titleChangedSpy.count == 1; }); - - compare(webEngineView.url, row.url); - tryCompare(webEngineView, "title", row.title); - verify(!webEngineView.action(WebEngineView.ViewSource).enabled); - } - function test_viewSourceCredentials() { var url = "http://user:passwd@httpbin.org/basic-auth/user/passwd"; @@ -145,12 +97,46 @@ TestWebEngineView { // The first titleChanged signal is emitted by adoptWebContents() tryVerify(function() { return titleChangedSpy.count >= 2; }); - compare(viewRequest.destination, WebEngineView.NewViewInTab); + compare(viewRequest.destination, WebEngineNewWindowRequest.InNewTab); verify(viewRequest.userInitiated); tryCompare(webEngineView, "url", "view-source:" + url.replace("user:passwd@", "")); tryCompare(webEngineView, "title", "view-source:" + url.replace("http://user:passwd@", "")); } + + function test_viewSourceURL_data() { + var testLocalUrl = "view-source:" + Qt.resolvedUrl("test1.html"); + var testLocalUrlWithoutScheme = "view-source:" + Qt.resolvedUrl("test1.html").toString().substring(7); + + return [ + { tag: "view-source:", userInputUrl: "view-source:", loadSucceed: true, url: "view-source:", title: "view-source:" }, + { tag: "view-source:about:blank", userInputUrl: "view-source:about:blank", loadSucceed: true, url: "view-source:about:blank", title: "view-source:about:blank" }, + { tag: testLocalUrl, userInputUrl: testLocalUrl, loadSucceed: true, url: testLocalUrl, title: "test1.html" }, + { tag: testLocalUrlWithoutScheme, userInputUrl: testLocalUrlWithoutScheme, loadSucceed: true, url: testLocalUrl, title: "test1.html" }, + { tag: "view-source:http://non.existent", userInputUrl: "view-source:http://non.existent", loadSucceed: false, url: "http://non.existent/", title: "non.existent" }, + { tag: "view-source:non.existent", userInputUrl: "view-source:non.existent", loadSucceed: false, url: "http://non.existent/", title: "non.existent" }, + ]; + } + + function test_viewSourceURL(row) { + WebEngine.settings.errorPageEnabled = true + webEngineView.url = row.userInputUrl; + + tryCompare(loadSpy, 'count', 2, 12000); + let load = loadSpy.signalArguments[1][0] + let expectedStatus = row.loadSucceed ? WebEngineView.LoadSucceededStatus : WebEngineView.LoadFailedStatus + compare(load.status, expectedStatus); + compare(load.isErrorPage, !row.loadSucceed); + tryVerify(function() { return titleChangedSpy.count == 1; }); + + compare(webEngineView.url, row.url); + tryCompare(webEngineView, "title", row.title); + if (row.loadSucceed) { + verify(!webEngineView.action(WebEngineView.ViewSource).enabled); + } else { + verify(webEngineView.action(WebEngineView.ViewSource).enabled); + } + } } } diff --git a/tests/auto/quick/qmltests/data/tst_webchannel.qml b/tests/auto/quick/qmltests/data/tst_webchannel.qml index 3ca3ccce1..780b55934 100644 --- a/tests/auto/quick/qmltests/data/tst_webchannel.qml +++ b/tests/auto/quick/qmltests/data/tst_webchannel.qml @@ -1,35 +1,11 @@ -/********************************************************************* -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> -** 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.2 - -import QtWebChannel 1.0 +// Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +import QtWebChannel Item { id: test @@ -81,6 +57,12 @@ Item { } function test_basic() { + webView.userScripts.collection = [ { + name: "qtwebchanneljs", + sourceUrl: Qt.resolvedUrl("qrc:/qtwebchannel/qwebchannel.js"), + injectionPoint: WebEngineScript.DocumentCreation, + worldId: WebEngineScript.MainWorld + }] webView.url = testUrl; verify(webView.waitForLoadSucceeded()); diff --git a/tests/auto/quick/qmltests/data/webchannel-test.html b/tests/auto/quick/qmltests/data/webchannel-test.html index 92966b24a..d8c3b1305 100644 --- a/tests/auto/quick/qmltests/data/webchannel-test.html +++ b/tests/auto/quick/qmltests/data/webchannel-test.html @@ -2,7 +2,6 @@ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript"> //BEGIN SETUP var channel = new QWebChannel(qt.webChannelTransport, function(channel) { diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/AlertDialog.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/AlertDialog.qml new file mode 100644 index 000000000..7d7efda0c --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/AlertDialog.qml @@ -0,0 +1,5 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +// Both dialogs are basically expected to behave in the same way from an API point of view +ConfirmDialog { } diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/ConfirmDialog.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/ConfirmDialog.qml new file mode 100644 index 000000000..6125d0b98 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/ConfirmDialog.qml @@ -0,0 +1,24 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQml +import QtTest +import "../../TestParams" + +QtObject { + property string text + property string title + signal accepted() + signal rejected() + + function open() { + JSDialogParams.dialogTitle = title; + JSDialogParams.dialogMessage = text; + JSDialogParams.dialogCount++; + if (JSDialogParams.shouldAcceptDialog) + accepted(); + else + rejected(); + } +} + diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml new file mode 100644 index 000000000..71da28843 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import "../../TestParams" + +QtObject { + signal folderSelected(var folder) + signal rejected() + + function open() { + FilePickerParams.directoryPickerOpened = true; + if (FilePickerParams.selectFiles) + folderSelected(FilePickerParams.selectedFilesUrl); + else + rejected(); + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/FilePicker.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/FilePicker.qml new file mode 100644 index 000000000..247088bcb --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/FilePicker.qml @@ -0,0 +1,24 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import "../../TestParams" + +QtObject { + property bool selectMultiple: false + property bool selectExisting: false + property bool selectFolder: false + property var nameFilters: [] + + signal filesSelected(var fileList) + signal rejected() + + function open() { + FilePickerParams.filePickerOpened = true; + FilePickerParams.nameFilters = nameFilters; + if (FilePickerParams.selectFiles) + filesSelected(FilePickerParams.selectedFilesUrl); + else + rejected(); + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/Menu.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/Menu.qml new file mode 100644 index 000000000..cd7ed4821 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/Menu.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2021 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 + +import QtQml +import "../../TestParams" + +QtObject { + id: menu + property string linkText: "" + property var mediaType: null + property string selectedText: "" + + signal done() + + function open() { + MenuParams.isMenuOpened = true; + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/MenuItem.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/MenuItem.qml new file mode 100644 index 000000000..67dab1bba --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/MenuItem.qml @@ -0,0 +1,8 @@ +// Copyright (C) 2021 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 + +import QtQml + +QtObject { + signal triggered() +} diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/PromptDialog.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/PromptDialog.qml new file mode 100644 index 000000000..81a63d918 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/PromptDialog.qml @@ -0,0 +1,27 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQml +import QtTest +import "../../TestParams" + +QtObject { + property string text + property string title + signal accepted() + signal rejected() + signal input(string text) + signal closing() + + function open() { + JSDialogParams.dialogTitle = title; + JSDialogParams.dialogMessage = text; + JSDialogParams.dialogCount++; + if (JSDialogParams.shouldAcceptDialog) { + input(JSDialogParams.inputForPrompt) + accepted(); + } else { + rejected(); + } + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml new file mode 100644 index 000000000..67d67dc40 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml @@ -0,0 +1,13 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +pragma Singleton +import QtQuick + +QtObject { + property var selectedFilesUrl: []; + property bool selectFiles: false; + property bool filePickerOpened: false; + property bool directoryPickerOpened: false; + property var nameFilters: []; +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/JSDialogParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/JSDialogParams.qml new file mode 100644 index 000000000..1033b509e --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/JSDialogParams.qml @@ -0,0 +1,12 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +pragma Singleton +import QtQml + +QtObject { + property string dialogMessage: ""; + property string dialogTitle: ""; + property bool shouldAcceptDialog: true; + property string inputForPrompt; + property int dialogCount: 0 +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/MenuParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/MenuParams.qml new file mode 100644 index 000000000..d8a01764c --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/MenuParams.qml @@ -0,0 +1,9 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +pragma Singleton +import QtQml + +QtObject { + property bool isMenuOpened: false; +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir b/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir new file mode 100644 index 000000000..2702ad30f --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir @@ -0,0 +1,5 @@ +# QML module so that the autotests can set testing parameters +module TestParams +singleton FilePickerParams 1.0 FilePickerParams.qml +singleton JSDialogParams 1.0 JSDialogParams.qml +singleton MenuParams 1.0 MenuParams.qml diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro deleted file mode 100644 index a50bfd7e6..000000000 --- a/tests/auto/quick/qmltests/qmltests.pro +++ /dev/null @@ -1,69 +0,0 @@ -include(../tests.pri) -include(../../shared/http.pri) - -QT += qmltest - -IMPORTPATH += $$PWD/data - -OTHER_FILES += \ - $$PWD/data/TestWebEngineView.qml \ - $$PWD/data/append-document-title.js \ - $$PWD/data/big-user-script.js \ - $$PWD/data/change-document-title.js \ - $$PWD/data/download.zip \ - $$PWD/data/directoryupload.html \ - $$PWD/data/favicon.html \ - $$PWD/data/forms.html \ - $$PWD/data/geolocation.html \ - $$PWD/data/javascript.html \ - $$PWD/data/link.html \ - $$PWD/data/localStorage.html \ - $$PWD/data/multifileupload.html \ - $$PWD/data/redirect.html \ - $$PWD/data/script-with-metadata.js \ - $$PWD/data/singlefileupload.html \ - $$PWD/data/test1.html \ - $$PWD/data/test2.html \ - $$PWD/data/test3.html \ - $$PWD/data/test4.html \ - $$PWD/data/test-iframe.html \ - $$PWD/data/keyboardModifierMapping.html \ - $$PWD/data/keyboardEvents.html \ - $$PWD/data/titleupdate.js \ - $$PWD/data/tst_action.qml \ - $$PWD/data/tst_activeFocusOnPress.qml \ - $$PWD/data/tst_audioMuted.qml \ - $$PWD/data/tst_contextMenu.qml \ - $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ - $$PWD/data/tst_download.qml \ - $$PWD/data/tst_filePicker.qml \ - $$PWD/data/tst_findText.qml \ - $$PWD/data/tst_focusOnNavigation.qml \ - $$PWD/data/tst_geopermission.qml \ - $$PWD/data/tst_getUserMedia.qml \ - $$PWD/data/tst_loadHtml.qml \ - $$PWD/data/tst_loadProgress.qml \ - $$PWD/data/tst_loadRecursionCrash.qml \ - $$PWD/data/tst_loadUrl.qml \ - $$PWD/data/tst_mouseMove.qml \ - $$PWD/data/tst_navigationHistory.qml \ - $$PWD/data/tst_navigationRequested.qml \ - $$PWD/data/tst_newViewRequest.qml \ - $$PWD/data/tst_notification.qml \ - $$PWD/data/tst_profile.qml \ - $$PWD/data/tst_properties.qml \ - $$PWD/data/tst_runJavaScript.qml \ - $$PWD/data/tst_scrollPosition.qml \ - $$PWD/data/tst_titleChanged.qml \ - $$PWD/data/tst_unhandledKeyEventPropagation.qml \ - $$PWD/data/tst_userScripts.qml \ - $$PWD/data/tst_viewSource.qml \ - $$PWD/data/tst_webchannel.qml \ - $$PWD/data/tst_settings.qml \ - $$PWD/data/tst_keyboardModifierMapping.qml \ - $$PWD/data/tst_keyboardEvents.qml \ - $$PWD/data/webchannel-test.html \ - $$PWD/data/icons/favicon.png \ - -load(qt_build_paths) -DEFINES += QUICK_TEST_SOURCE_DIR=\\\"$$re_escape($$PWD$${QMAKE_DIR_SEP}data)\\\" diff --git a/tests/auto/quick/qmltests/resources/server.key b/tests/auto/quick/qmltests/resources/server.key new file mode 100644 index 000000000..9bf87aee3 --- /dev/null +++ b/tests/auto/quick/qmltests/resources/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAqAygFPG5ILLb3G51D0OIN4Kpm5t3Oh1nByTnvi1kMz+sCBBd +CSugt4NnKkB6kiGtMEsrEm1/xg8Bkfbpet3v3+jAidRpjvCISqy3Z9D1cgCFM46h +iob/AvLZpqITiAgsU4fJ4auuIKhFplIGrIKMv2gK8haoBGBoRUD1RM+irwjEr6TN +XTQt2Ap+Ouxs53NLPhAOgumpfzzRR8/Umbhen+G5MhH+XTzzreiClz2V6A79ePJj +y1uQ8NJ79feOOWBDRizRDWwxsnNd24GjkpvcaTwafiK6Vdqeub+XTtiB5RPal2on +Cj0TQDcnaacecl/zmUWsIFNkNJWDcd3/vEdyOQIDAQABAoIBAQCW93icOCdim6tu +FIDu7HEjxSsPUpPCToWu4lWaAHcinxGx0NlzkpD4K4DzcSdrvfszBmQ0UtBVokd7 +1IAdU+HZmePWLk+CDM2zoAPHrO3Cs3r2PS0cIHhZMsearcG0E/uWMseHB08PoXuo +lcnPEhzVGueyYe4guGcTx+5PGeUBLf+fJcEc3rIQnT2LYulM2aqBZSQM3jRUaPYs +F0awDpCNwajW/Bt2VB14Pr+H5MJ+WSznFCqW7SolBkqDGfKckXPSHgX6xZ0y7VCI +MM8vwlVI4mPkaHvSQMSI8vS4Qh+SGQCSs/AuuNLjjPoz1YotV3Ih4YbLj6BjFP2g +CrqzT6VNAoGBANOHmsqE0nRkLzonTDrMdla5b0TjTxwtNM5DjLgJa6UBBqPe+1Lv +JFoBP9bIfYDRWZOZrxXItfMmM43nK/ST6Xqgx1IpHUCLKVr2pA9RXrP+m4oawfgn +frW212fHibeOYiLy+DaQXQ0VRFxsc/VbwKVyVlMEcNg3N93x2E67M7vjAoGBAMtg +7wDa+5gjwuyNr7LKkp5VDTmtKQhoDtg4sw6MSQSMF6fJT9Z4kGTZ23+G85/LsM/k +iXbceabGJ0CQJvGn6oW4dI2Ut2c2nCNVbQCxJ6Nyn/yW7bRLShMnwXvbGAVxVUax +5ohJPZGJ8ar2CP76A0bkvm2Nwylq2gp6Y8h7+iwzAoGBAKizwfQ6sk45iKDsrpNG +dir8gY2DbJigRTksDpLIkJ1skAspz295YpiV3oBCLjYKwVJCg6zwAo0FrqBB+oB5 +ZwByMgWI3NeZJUZy5q2Ay/Lp4MroRELR3PC3/lu6fE90szgEZ4m84TmJ+Jdtt527 +q41H/yj+pbELePb95vIDw2LZAoGBAJBZ+MmupCzUFSI5Xp+UUIS48W4ijaE92mt1 +swF8aMcleBTLOjOL11D9oGHfs0OUG6czGq6WxnGs62dT6ZBUEo1e4rsq9xH3HNOn +anq3Qt8sGIn7xjPVzHnUGeyDEYWrb0+CLZJGCcEnG7SwdKolYfYLnW281Oysvp35 +SKGf/W0pAoGAa2+sZmhb1mpGAf6Bi4z+uym/6qOJmG6CnrBSM9e/r8nujwFVkCYF +3iz48qx3GbuliO6za8aM1drX2u8KWp1uP5KzwYvtW5SfpQ1eusFblHEYQQNRcKLT +j/wZBXnU961eMKkkTe2XsPirO8rVhVmxuFLqT/aEPffcragQFFIGOEQ= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/quick/qmltests/resources/server.pem b/tests/auto/quick/qmltests/resources/server.pem new file mode 100644 index 000000000..a201ed08e --- /dev/null +++ b/tests/auto/quick/qmltests/resources/server.pem @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIUFZEIIzeR7lEA10rb14w7MfhP87MwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy +bGluMRUwEwYDVQQKDAxUaGVRdENvbXBhbnkxEjAQBgNVBAsMCXdlYmVuZ2luZTAe +Fw0yMTA1MTAyMTM1MTJaFw0yMjA1MTAyMTM1MTJaMGAxCzAJBgNVBAYTAkRFMQ8w +DQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEVMBMGA1UECgwMVGhlUXRD +b21wYW55MRgwFgYDVQQDDA93ZWJlbmdpbmUucXQuaW8wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCoDKAU8bkgstvcbnUPQ4g3gqmbm3c6HWcHJOe+LWQz +P6wIEF0JK6C3g2cqQHqSIa0wSysSbX/GDwGR9ul63e/f6MCJ1GmO8IhKrLdn0PVy +AIUzjqGKhv8C8tmmohOICCxTh8nhq64gqEWmUgasgoy/aAryFqgEYGhFQPVEz6Kv +CMSvpM1dNC3YCn467Gznc0s+EA6C6al/PNFHz9SZuF6f4bkyEf5dPPOt6IKXPZXo +Dv148mPLW5Dw0nv19445YENGLNENbDGyc13bgaOSm9xpPBp+IrpV2p65v5dO2IHl +E9qXaicKPRNANydppx5yX/OZRawgU2Q0lYNx3f+8R3I5AgMBAAGjMzAxMBoGA1Ud +EQQTMBGCD3dlYmVuZ2luZS5xdC5pbzATBgNVHSUEDDAKBggrBgEFBQcDATANBgkq +hkiG9w0BAQsFAAOCAQEAjThKpP0sBv1vEmaqBc1wTu//7RHmFcoStTt3scADzb2C +9gjOVC4NzxBneLkv01444Z1p/Iiu/ZZ+VKu7aJElJgnBWEisYwJ09t3cdZRA0UY7 +XRvTVAqV0OlsB1Jn0afE+aTLGjWo+jSYzua0O+NK74e23p9jkdSmXxH9w0FB/oyM +FGIOFnnfP0+QR4ZVvAGk2H60tBHQKmCM6b87TiD4GQIfOghCQWH+qJYSuyGu4hkE +uis+n1KHHhed3GIJOHpm7gt1C9qtjcp1nOpv0ycQjfc9CGvr02BcQjhMeO65hX0A +TvCgKN9/XMFv5jwwjjPCL12GBhwnN2k9hM/tEYpe2A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOzCCAiMCFDwWg4NZxCplj3qyBxAUTi1wmj4jMA0GCSqGSIb3DQEBCwUAMFox +CzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEV +MBMGA1UECgwMVGhlUXRDb21wYW55MRIwEAYDVQQLDAl3ZWJlbmdpbmUwHhcNMjEw +NTEwMjEzMTE4WhcNMjIwNTEwMjEzMTE4WjBaMQswCQYDVQQGEwJERTEPMA0GA1UE +CAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFTATBgNVBAoMDFRoZVF0Q29tcGFu +eTESMBAGA1UECwwJd2ViZW5naW5lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAuc/8xVrfSzOsI6kYul+o1QIPBh1I86eQm1PhTBDMAAPHuzyPaEMgBkn2 +XAUmvkynGpNioaJDU2ndV2fBHvsoeQCdNNmjFTe1rKYjrN6U2X5KoYSzN93TOYzK +aR38fEFx+w4qV76nnxSjYtGNe9z74GrfWFMdDQ0NJKzvaO4gaZ+OOg0OzWy4MJQ0 +aINo3UV55Y7Nt92AxFweiuHucKu+rjf3BX7n0Af/Tcs2c84f0R3HA7euReSibVvX +f33eHLRKwu2bvDjXiUzOdkxBn9GTo6Q09LyY6wDG0ZdWnyCKj3NBQKBVrq+bs3Q0 +ATsWhj/PvYlZhhZh4EOlqYOhCpwv4wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCC +pLSFGJcG0zhHW+2A6ogmpn2tA8gKUZx7f0J1nwgPEoAXQqWQv/299ZtmWfMKHUkk +ygG4u80C87wWPH42XWXo/KDrP9iYzoqAvtqbRuPG9PAxefQ/JUSnuhikA51g9+Mu +IDKKKSI+y/JW9u0Qo77fp/5n2DaFn5B+pBYvn/xLfaEa9bRdJMTEMsElGbPBzMZd +I/7X6B78X6Ow5TuRKSeZA7E1AZ/+e5A4Hj65bLAugoSKz3zaS0dV26LwAo18c2zP +TqtwHyIVj4QCoI6Z694q9KH4Pkml3fz8VSkk+MvZMWapvUhHu/DneTgqGbp9POYg +nx6oWME6idhnvN6DljxB +-----END CERTIFICATE----- diff --git a/tests/auto/quick/qmltests/tst_qmltests.cpp b/tests/auto/quick/qmltests/tst_qmltests.cpp index 5677f9047..9e928157e 100644 --- a/tests/auto/quick/qmltests/tst_qmltests.cpp +++ b/tests/auto/quick/qmltests/tst_qmltests.cpp @@ -1,39 +1,23 @@ -/**************************************************************************** -** -** 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) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <httpserver.h> -#include <QtCore/QScopedPointer> -#include <QTemporaryDir> +#if QT_CONFIG(ssl) +#include <httpsserver.h> +#endif + +#include <QtCore/qscopedpointer.h> +#include <QtCore/qtemporarydir.h> +#include <QtGui/private/qinputmethod_p.h> +#include <QtQml/qqmlengine.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickwindow.h> #include <QtQuickTest/quicktest.h> -#include <QtWebEngine/QQuickWebEngineProfile> -#include <QQmlEngine> -#include "qt_webengine_quicktest.h" +#include <QtTest/qtest.h> +#include <QtWebEngineQuick/qquickwebengineprofile.h> +#include <QtWebEngineQuick/qtwebenginequickglobal.h> +#include <qt_webengine_quicktest.h> #if defined(Q_OS_LINUX) && defined(QT_DEBUG) #include <fcntl.h> @@ -41,6 +25,19 @@ #include <unistd.h> #endif +class Setup : public QObject +{ + Q_OBJECT +public: + Setup() { } + +public slots: + void qmlEngineAvailable(QQmlEngine *engine) + { + engine->addImportPath(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + "/mock-delegates"); + } +}; + #if defined(Q_OS_LINUX) && defined(QT_DEBUG) static bool debuggerPresent() { @@ -108,10 +105,125 @@ public: return tempDir.isValid() ? tempDir.path() : QString(); } + Q_INVOKABLE QUrl pathUrl(const QString &filename = QString()) + { + Q_ASSERT(tempDir.isValid()); + return filename.isEmpty() ? QUrl::fromLocalFile(tempDir.path()) + : QUrl::fromLocalFile(tempDir.filePath(filename)); + } + + Q_INVOKABLE void removeRecursive(const QString dirname) + { + QDir dir(dirname); + QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); + for (int i = 0; i < entries.size(); ++i) { + if (entries[i].isDir()) + removeRecursive(entries[i].filePath()); + else + dir.remove(entries[i].fileName()); + } + QDir().rmdir(dirname); + } + + Q_INVOKABLE void createDirectory(const QString dirname) { QDir(tempDir.path()).mkdir(dirname); } + private: QTemporaryDir tempDir; }; +class TestInputContext : public QPlatformInputContext { + Q_OBJECT + +public: + TestInputContext() = default; + ~TestInputContext() { release(); } + + Q_INVOKABLE void create() + { + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = this; + } + + Q_INVOKABLE void release() + { + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = nullptr; + } + + void showInputPanel() override { m_visible = true; } + void hideInputPanel() override { m_visible = false; } + bool isInputPanelVisible() const override { return m_visible; } + +private: + bool m_visible = false; +}; + +QT_BEGIN_NAMESPACE +namespace QTest { + int Q_TESTLIB_EXPORT defaultMouseDelay(); +} +QT_END_NAMESPACE + +class TestInputEvent : public QObject { + Q_OBJECT + +public: + TestInputEvent() = default; + + Q_INVOKABLE bool mouseMultiClick(QObject *item, qreal x, qreal y, int clickCount) + { + QTEST_ASSERT(item); + + QWindow *view = eventWindow(item); + if (!view) + return false; + + for (int i = 0; i < clickCount; ++i) { + mouseEvent(QMouseEvent::MouseButtonPress, view, item, QPointF(x, y)); + mouseEvent(QMouseEvent::MouseButtonRelease, view, item, QPointF(x, y)); + } + QTest::lastMouseTimestamp += QTest::mouseDoubleClickInterval; + + return true; + } + +private: + QWindow *eventWindow(QObject *item = nullptr) + { + QWindow *window = qobject_cast<QWindow *>(item); + if (window) + return window; + + QQuickItem *quickItem = qobject_cast<QQuickItem *>(item); + if (quickItem) + return quickItem->window(); + + QQuickItem *testParentItem = qobject_cast<QQuickItem *>(parent()); + if (testParentItem) + return testParentItem->window(); + + return nullptr; + } + + void mouseEvent(QEvent::Type type, QWindow *window, QObject *item, const QPointF &_pos) + { + QTest::qWait(QTest::defaultMouseDelay()); + QTest::lastMouseTimestamp += QTest::defaultMouseDelay(); + + QPoint pos; + QQuickItem *sgitem = qobject_cast<QQuickItem *>(item); + if (sgitem) + pos = sgitem->mapToScene(_pos).toPoint(); + + QMouseEvent me(type, pos, window->mapFromGlobal(pos), Qt::LeftButton, Qt::LeftButton, {}); + me.setTimestamp(++QTest::lastMouseTimestamp); + + QSpontaneKeyEvent::setSpontaneous(&me); + if (!qApp->notify(window, &me)) + qWarning("Mouse click event not accepted by receiving window"); + } +}; + int main(int argc, char **argv) { #if defined(Q_OS_LINUX) && defined(QT_DEBUG) @@ -123,35 +235,41 @@ int main(int argc, char **argv) sigaction(SIGSEGV, &sigAction, 0); #endif - - QScopedPointer<Application> app; - + QtWebEngineQuick::initialize(); // Force to use English language for testing due to error message checks QLocale::setDefault(QLocale("en")); - static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; - 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(); \ + static QByteArrayList params = {QByteArrayLiteral("--webEngineArgs"),QByteArrayLiteral("--use-fake-device-for-media-stream")}; + QList<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(); + Application app(w_argc, const_cast<char **>(w_argv.data())); - if (!QCoreApplication::instance()) { - app.reset(new Application(w_argc, const_cast<char **>(w_argv.data()))); - } - QtWebEngine::initialize(); QQuickWebEngineProfile::defaultProfile()->setOffTheRecord(true); qmlRegisterType<TempDir>("Test.util", 1, 0, "TempDir"); + qmlRegisterType<TestInputContext>("Test.util", 1, 0, "TestInputContext"); + qmlRegisterType<TestInputEvent>("Test.util", 1, 0, "TestInputEvent"); QTEST_SET_MAIN_SOURCE_PATH qmlRegisterSingletonType<HttpServer>("Test.Shared", 1, 0, "HttpServer", [&] (QQmlEngine *, QJSEngine *) { auto server = new HttpServer; - server->setResourceDirs({ TESTS_SHARED_DATA_DIR, QUICK_TEST_SOURCE_DIR }); + server->setResourceDirs( + { server->sharedDataDir(), + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + QLatin1String("/data") }); return server; }); - int i = quick_test_main(argc, argv, "qmltests", QUICK_TEST_SOURCE_DIR); +#if QT_CONFIG(ssl) + qmlRegisterSingletonType<HttpsServer>( + "Test.Shared", 1, 0, "HttpsServer", [&](QQmlEngine *, QJSEngine *) { + return new HttpsServer(":/resources/server.pem", ":/resources/server.key", ""); + }); +#endif + Setup setup; + int i = quick_test_main_with_setup( + argc, argv, "qmltests", + qPrintable(QT_TESTCASE_BUILDDIR + QLatin1String("/webengine.qmltests")), &setup); return i; } |