Revision control
Copy as Markdown
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtWebView
import QtTest
import QuickWebViewTest
RowLayout {
id: root
WebViewTestCase {
name: "HiddenNavigation"
function test_loadEmptyPageViewHidden() {
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
}
}
WebViewTestCase {
name: "Navigation"
when: windowShown
function test_startupState() {
compare(webView.canGoBack, false);
compare(webView.canGoForward, false);
compare(webView.loading, false);
compare(webView.url, "");
}
function test_loadNonexistentFileUrl() {
webView.url = Qt.resolvedUrl("file_that_does_not_exist.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadFailedStatus));
}
function test_backAndForward() {
let page1 = WebViewTestUtils.makeTestFileUrl("basic_page.html");
let page2 = WebViewTestUtils.makeTestFileUrl("basic_page2.html");
webView.url = page1;
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.expectedUrl(page1));
verify(!webView.canGoBack);
verify(!webView.canGoForward);
webView.url = page2;
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.expectedUrl(page2));
verify(webView.canGoBack);
verify(!webView.canGoForward);
webView.goBack();
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(!webView.canGoBack);
verify(webView.canGoForward);
webView.goForward();
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.canGoBack);
verify(!webView.canGoForward);
}
function test_reload() {
let u = WebViewTestUtils.makeTestFileUrl("basic_page.html");
webView.url = u;
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.expectedUrl(u));
webView.reload();
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.expectedUrl(u));
}
function test_loadProgress() {
// TODO check for values less than 100. Is that guaranteed to happen on all platforms?
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
verify(webView.loadProgressSpy.signalArguments.length >= 1);
compare(webView.loadProgress, 100);
}
}
WebViewTestCase {
name: "PageData"
function test_title() {
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page2.html");
if (webView.pluginIs("webengine")
|| webView.pluginIs("android_view")
|| webView.pluginIs("webview2") ) {
// Signal does not get emitted on some platforms, because page has no <title>
// TODO maybe fix that?
webView.titleSpy.wait();
webView.titleSpy.clear();
}
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
webView.titleSpy.wait();
tryCompare(webView, "title", "Basic Page");
// No titleChanged signal for failed load
webView.titleSpy.clear();
webView.loadingStatuses = [];
webView.urls = [];
webView.url = Qt.resolvedUrl("file_that_does_not_exist.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadFailedStatus));
if (webView.pluginIs("android_view")
|| webView.pluginIs("webview2")) {
webView.titleSpy.wait();
} else {
wait(200);
compare(webView.titleSpy.signalArguments.length, 0);
}
}
}
WebViewTestCase {
name: "UserAgent"
function test_changeUserAgent() {
// Wait for backend to initialize. TODO maybe add signal for that?
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
let waitForBackend = function() { return webView.httpUserAgent.length != 0; };
tryVerify(waitForBackend, 10000);
let defaultAgent = webView.httpUserAgent.slice(0);
// Test setting at object creation
webView.destroy();
webView = webViewComponent.createObject(root, { httpUserAgent: "TestAgent" });
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
tryVerify(waitForBackend, 10000);
verify(webView.httpUserAgent == "TestAgent");
// Test that the setting is not global
webView.destroy();
webView = webViewComponent.createObject(root);
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
if (webView.pluginIs("webengine")) {
expectFail("", "The setting is global for the WebEngine backend");
}
verify(webView.httpUserAgent == defaultAgent);
// Test setting dynamically
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
webView.httpUserAgent = "TestAgent";
verify(webView.httpUserAgent == "TestAgent");
}
}
WebViewTestCase {
name: "JavaScript"
function test_javascriptSettings_data() {
return [
{ tag: "Test JS enabled", jsEnabled: true, expectedTitle: "JavaScript Test" },
{ tag: "Test JS disabled", jsEnabled: false, expectedTitle: "JavaScript" },
]
}
function test_javascriptSettings(data) {
webView.settings.javaScriptEnabled = data.jsEnabled;
webView.url = WebViewTestUtils.makeTestFileUrl("javascript.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
tryCompare(webView, "title", data.expectedTitle);
}
function test_runJavaScript() {
webView.url = WebViewTestUtils.makeTestFileUrl("basic_page.html");
verify(webView.waitForLoad(WebViewLoadRequest.LoadStatus.LoadSucceededStatus));
var title = undefined;
webView.runJavaScript("document.title", function(result) {
title = result;
});
tryVerify(function() { return title === "Basic Page" }, 12000);
}
}
WebViewTestCase {
name: "Cookies"
function test_setAndDeleteCookies() {
let cookieList = [
{ domain: ".example1.com", name: "TestCookie1", value: "testValue1" },
{ domain: ".example2.com", name: "TestCookie2", value: "testValue2" },
{ domain: ".example3.com", name: "TestCookie3", value: "testValue3" }
]
let deletedCookie = { domain: ".example3.com", name: "TestCookie3", value: "testValue3" };
for (const cookie of cookieList) {
webView.setCookie(cookie.domain, cookie.name, cookie.value);
}
tryCompare(webView.cookieAddedSpy.signalArguments, "length", cookieList.length, 10000);
// Delete an existing cookie
webView.deleteCookie(deletedCookie.domain, deletedCookie.name);
webView.cookieRemovedSpy.wait();
compare(webView.cookieRemovedSpy.signalArguments[0][0], deletedCookie.domain);
compare(webView.cookieRemovedSpy.signalArguments[0][1], deletedCookie.name);
// Try to delete a cookie using a name that has not been set
webView.deleteCookie(".example.com", "NewCookieName");
wait(200); // We need to check that no signal has been emitted. Wait time is arbitrary
compare(webView.cookieRemovedSpy.signalArguments.length, 1);
// Try to delete a cookie using a domain that has not been set
webView.deleteCookie("new.domain.com", "TestCookie2");
wait(200);
compare(webView.cookieRemovedSpy.signalArguments.length, 1);
webView.deleteAllCookies();
if (webView.pluginIs("android_view")) {
expectFail("", "Notification for deleteAllCookies() is not implemented on Android yet!");
}
tryCompare(webView.cookieRemovedSpy.signalArguments, "length", 3);
}
function test_setCookie() {
// These should not be accepted, and shouldn't cause a crash
webView.setCookie("", "", "testValue");
webView.setCookie(".fake.domain", "", "testValue");
webView.setCookie("", "fakeName", "testValue");
wait(200);
compare(webView.cookieAddedSpy.signalArguments.length, 0);
// This should be accepted, as a cookie with an empty value is valid
webView.setCookie(".fake.domain", "fakeName", "");
tryCompare(webView.cookieAddedSpy.signalArguments, "length", 1)
}
}
}