Revision control

Copy as Markdown

// Copyright (C) 2015 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qdir.h>
#include <QtCore/qtemporarydir.h>
#include <QtCore/qfileinfo.h>
#include <QtWebView/qwebview.h>
#include <QtWebView/qwebviewsettings.h>
#include <QtWebView/qwebviewloadinginfo.h>
#include <QtWebView/private/qwebviewfactory_p.h>
#include <testutil.h>
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
#include <QtCore/private/qjnihelpers_p.h>
#define ANDROID_REQUIRES_API_LEVEL(N) \
if (QtAndroidPrivate::androidSdkVersion() < N) \
QSKIP("This feature is not supported on this version of Android");
#else
#define ANDROID_REQUIRES_API_LEVEL(N)
#endif
class TestWebView : public QWebView {
public:
TestWebView() : QWebView() { settings()->setAttribute(QWebViewSettings::WebAttribute::AllowFileAccess, true); };
QSignalSpy urlSpy = QSignalSpy(this, SIGNAL(urlChanged(QUrl)));
QSignalSpy loadingSpy = QSignalSpy(this, SIGNAL(loadingChanged(QWebViewLoadingInfo)));
QSignalSpy titleSpy = QSignalSpy(this, SIGNAL(titleChanged(QString)));
};
class tst_QWebView : public QObject
{
Q_OBJECT
public:
tst_QWebView() : m_cacheLocation(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) {}
private slots:
void initTestCase();
void startupState();
void load();
void loadNonexistentFileUrl();
void loadHtml_data();
void loadHtml();
void loadRequest();
void backAndForward();
void reload();
void runJavaScript();
void setAndDeleteCookie();
private:
const QString m_cacheLocation;
};
void tst_QWebView::initTestCase()
{
if (!qEnvironmentVariableIsEmpty("QEMU_LD_PREFIX"))
QSKIP("This test is unstable on QEMU, so it will be skipped.");
if (!QFileInfo(m_cacheLocation).isDir()) {
QDir dir;
QVERIFY(dir.mkpath(m_cacheLocation));
}
}
void tst_QWebView::startupState()
{
QWebView webView;
QVERIFY(!webView.canGoBack());
QVERIFY(!webView.canGoForward());
QVERIFY(!webView.isLoading());
QCOMPARE(webView.url(), QUrl());
}
void tst_QWebView::load()
{
TestWebView webView;
webView.setUrl(makeTestFileUrl("basic_page.html"));
QTRY_COMPARE(webView.loadingSpy.size(), 2);
QCOMPARE(webView.urlSpy.size(), 1);
QCOMPARE(webView.loadProgress(), 100);
QCOMPARE(webView.loadingSpy[0][0].value<QWebViewLoadingInfo>().status(), QWebViewLoadingInfo::LoadStatus::Started);
QCOMPARE(webView.loadingSpy[1][0].value<QWebViewLoadingInfo>().status(), QWebViewLoadingInfo::LoadStatus::Succeeded);
QCOMPARE(webView.title(), QStringLiteral("Basic Page"));
}
void tst_QWebView::loadNonexistentFileUrl()
{
TestWebView webView;
webView.setUrl(QUrl::fromLocalFile("file_that_does_not_exist.html"));
QTRY_COMPARE(webView.loadingSpy.size(), 2);
QCOMPARE(webView.loadingSpy[1][0].value<QWebViewLoadingInfo>().status(), QWebViewLoadingInfo::LoadStatus::Failed);
}
void tst_QWebView::loadHtml_data()
{
QTest::addColumn<QByteArray>("content");
QTest::addColumn<QUrl>("loadUrl");
QTest::addColumn<QUrl>("resultUrl");
const QByteArray content(
QByteArrayLiteral("<html><title>WebViewTitle</title>"
"<body><span style=\"color:#ff0000\">Hello</span></body></html>"));
QByteArray encoded("data:text/html;charset=UTF-8,");
encoded.append(content.toPercentEncoding());
if (!QWebViewFactory::loadedPluginHasKey("webkit")) {
QTest::newRow("set content without base url") << content << QUrl() << QUrl(encoded);
} else {
QTest::newRow("set content without base url") << content << QUrl() << QUrl("about:blank");
}
QTest::newRow("set content with data base url") << content << QUrl(encoded) << QUrl(encoded);
if (!QWebViewFactory::loadedPluginHasKey("webview2")) {
QTest::newRow("set content with non-data base url")
<< content << QUrl("http://foobar.com/") << QUrl("http://foobar.com/");
} else {
QTest::newRow("set content with non-data base url")
<< content << QUrl("http://foobar.com/") << QUrl(encoded);
}
}
void tst_QWebView::loadHtml()
{
QFETCH(QByteArray, content);
QFETCH(QUrl, loadUrl);
QFETCH(QUrl, resultUrl);
TestWebView view;
view.loadHtml(content, loadUrl);
QTRY_COMPARE(view.loadingSpy.size(), 2);
QVERIFY(!view.isLoading());
QCOMPARE(view.loadProgress(), 100);
QTRY_COMPARE(view.title(), QStringLiteral("WebViewTitle"));
// take load finished
const QWebViewLoadingInfo &lr = view.loadingSpy.at(1).at(0).value<QWebViewLoadingInfo>();
QCOMPARE(lr.status(), QWebViewLoadingInfo::LoadStatus::Succeeded);
bool called = false;
QUrl url;
auto callback = [&](const QVariant &result) {
called = true;
url = result.value<QUrl>();
};
view.runJavaScript("document.baseURI", callback);
QTRY_COMPARE(called, true);
QCOMPARE(url, resultUrl);
QVERIFY(view.url().isValid());
QCOMPARE(view.url(), resultUrl);
}
void tst_QWebView::loadRequest()
{
// LoadSucceeded
{
QTemporaryFile file(m_cacheLocation + QStringLiteral("/XXXXXXfile.html"));
QVERIFY2(file.open(),
qPrintable(QStringLiteral("Cannot create temporary file:") + file.errorString()));
file.write("<html><head><title>FooBar</title></head><body/></html>");
const QString fileName = file.fileName();
file.close();
QWebView view;
view.settings()->setAttribute(QWebViewSettings::WebAttribute::AllowFileAccess, true);
view.settings()->setAttribute(QWebViewSettings::WebAttribute::LocalContentCanAccessFileUrls,
true);
const QUrl url = QUrl::fromLocalFile(fileName);
QSignalSpy loadChangedSignalSpy(&view, SIGNAL(loadingChanged(QWebViewLoadingInfo)));
view.setUrl(url);
QTRY_COMPARE(loadChangedSignalSpy.size(), 2);
QVERIFY(!view.isLoading());
QCOMPARE(view.loadProgress(), 100);
QTRY_COMPARE(view.title(), QStringLiteral("FooBar"));
QCOMPARE(view.url(), url);
{
const QList<QVariant> &loadStartedArgs = loadChangedSignalSpy.takeFirst();
const QWebViewLoadingInfo &lr = loadStartedArgs.at(0).value<QWebViewLoadingInfo>();
QCOMPARE(lr.status(), QWebViewLoadingInfo::LoadStatus::Started);
}
{
const QList<QVariant> &loadStartedArgs = loadChangedSignalSpy.takeFirst();
const QWebViewLoadingInfo &lr = loadStartedArgs.at(0).value<QWebViewLoadingInfo>();
QCOMPARE(lr.status(), QWebViewLoadingInfo::LoadStatus::Succeeded);
}
}
// LoadFailed
{
QWebView view;
view.settings()->setAttribute(QWebViewSettings::WebAttribute::AllowFileAccess, true);
view.settings()->setAttribute(QWebViewSettings::WebAttribute::LocalContentCanAccessFileUrls,
true);
QSignalSpy loadChangedSignalSpy(&view, SIGNAL(loadingChanged(QWebViewLoadingInfo)));
view.setUrl(QUrl(QStringLiteral("file:///file_that_does_not_exist.html")));
QTRY_VERIFY(!view.isLoading());
QTRY_COMPARE(loadChangedSignalSpy.size(), 2);
{
const QList<QVariant> &loadStartedArgs = loadChangedSignalSpy.takeFirst();
const QWebViewLoadingInfo &lr = loadStartedArgs.at(0).value<QWebViewLoadingInfo>();
QCOMPARE(lr.status(), QWebViewLoadingInfo::LoadStatus::Started);
}
{
const QList<QVariant> &loadStartedArgs = loadChangedSignalSpy.takeFirst();
const QWebViewLoadingInfo &lr = loadStartedArgs.at(0).value<QWebViewLoadingInfo>();
QCOMPARE(lr.status(), QWebViewLoadingInfo::LoadStatus::Failed);
}
if (QWebViewFactory::loadedPluginHasKey("webengine"))
QCOMPARE(view.loadProgress(), 100);
}
}
void tst_QWebView::backAndForward()
{
TestWebView webView;
QUrl page1 = makeTestFileUrl("basic_page.html");
QUrl page2 = makeTestFileUrl("basic_page2.html");
webView.setUrl(page1);
QTRY_COMPARE(webView.loadingSpy.size(), 2);
QVERIFY(!webView.canGoBack());
QVERIFY(!webView.canGoForward());
webView.setUrl(page2);
QTRY_COMPARE(webView.loadingSpy.size(), 4);
QVERIFY(webView.canGoBack());
QVERIFY(!webView.canGoForward());
webView.goBack();
QTRY_COMPARE(webView.loadingSpy.size(), 6);
QVERIFY(!webView.canGoBack());
QVERIFY(webView.canGoForward());
webView.goForward();
QTRY_COMPARE(webView.loadingSpy.size(), 8);
QVERIFY(webView.canGoBack());
QVERIFY(!webView.canGoForward());
}
void tst_QWebView::reload()
{
TestWebView webView;
QUrl url = makeTestFileUrl("basic_page.html");
webView.setUrl(url);
QTRY_COMPARE(webView.loadingSpy.size(), 2);
webView.reload();
QTRY_COMPARE(webView.loadingSpy.size(), 4);
QCOMPARE(webView.loadingSpy[3][0].value<QWebViewLoadingInfo>().status(), QWebViewLoadingInfo::LoadStatus::Succeeded);
QCOMPARE(webView.url(), url);
}
void tst_QWebView::runJavaScript()
{
ANDROID_REQUIRES_API_LEVEL(19)
QWebView view;
view.show();
view.loadHtml(QString("<html><head><title>WebViewTitle</title></head><body/></html>"));
QTRY_COMPARE(view.loadProgress(), 100);
QTRY_VERIFY(!view.isLoading());
QTRY_COMPARE(view.title(), "WebViewTitle");
bool callbackCalled = false;
view.runJavaScript(QString(QLatin1String("document.title")), [&callbackCalled](const QVariant &result) {
QCOMPARE(result.toString(), "WebViewTitle");
callbackCalled = true;
});
QTRY_VERIFY(callbackCalled);
}
void tst_QWebView::setAndDeleteCookie()
{
QWebView view;
view.settings()->setAttribute(QWebViewSettings::WebAttribute::AllowFileAccess, true);
view.settings()->setAttribute(QWebViewSettings::WebAttribute::LocalContentCanAccessFileUrls,
true);
view.settings()->setAttribute(QWebViewSettings::WebAttribute::LocalStorageEnabled, true);
QSignalSpy cookieAddedSpy(&view, SIGNAL(cookieAdded(QString,QString)));
QSignalSpy cookieRemovedSpy(&view, SIGNAL(cookieRemoved(QString,QString)));
view.setCookie(".example.com", "TestCookie", "testValue");
view.setCookie(".example2.com", "TestCookie2", "testValue2");
view.setCookie(".example3.com", "TestCookie3", "testValue3");
QTRY_COMPARE(cookieAddedSpy.size(), 3);
view.deleteCookie(".example.com", "TestCookie");
QTRY_COMPARE(cookieRemovedSpy.size(), 1);
// deleting a cookie using a name that has not been set
view.deleteCookie(".example.com", "NewCookieName");
QTRY_COMPARE(cookieRemovedSpy.size(), 1);
// deleting a cookie using a domain that has not been set
view.deleteCookie(".new.domain.com", "TestCookie2");
QTRY_COMPARE(cookieRemovedSpy.size(), 1);
view.deleteAllCookies();
if (QWebViewFactory::loadedPluginHasKey("android_view"))
QEXPECT_FAIL("", "Notification for deleteAllCookies() is not implemented on Android, yet!", Continue); // FIXME
QTRY_COMPARE(cookieRemovedSpy.size(), 3);
}
QTEST_MAIN(tst_QWebView)
#include "tst_qwebview.moc"