summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/loadsignals/tst_loadsignals.cpp')
-rw-r--r--tests/auto/widgets/loadsignals/tst_loadsignals.cpp523
1 files changed, 406 insertions, 117 deletions
diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
index 32bf53931..6140b3766 100644
--- a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
+++ b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
@@ -1,41 +1,63 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QtTest>
#include "httpserver.h"
-#include "../util.h"
+#include <util.h>
#include "qdebug.h"
+#include "qwebengineloadinginfo.h"
#include "qwebenginepage.h"
#include "qwebengineprofile.h"
#include "qwebenginesettings.h"
#include "qwebengineview.h"
+enum {
+ LoadStarted = QWebEngineLoadingInfo::LoadStartedStatus,
+ LoadStopped = QWebEngineLoadingInfo::LoadStoppedStatus,
+ LoadSucceeded = QWebEngineLoadingInfo::LoadSucceededStatus,
+ LoadFailed = QWebEngineLoadingInfo::LoadFailedStatus,
+};
+static const QList<int> SignalsOrderOnce({ LoadStarted, LoadSucceeded});
+static const QList<int> SignalsOrderTwice({ LoadStarted, LoadSucceeded, LoadStarted, LoadSucceeded });
+static const QList<int> SignalsOrderOnceFailure({ LoadStarted, LoadFailed });
+static const QList<int> SignalsOrderTwiceWithFailure({ LoadStarted, LoadSucceeded, LoadStarted, LoadFailed });
+
+class TestPage : public QWebEnginePage
+{
+public:
+ QSet<QUrl> blacklist;
+ int navigationRequestCount = 0;
+ QList<int> signalsOrder;
+ QList<int> loadProgress;
+ QList<QWebEngineLoadingInfo> loadingInfos;
+
+ explicit TestPage(QObject *parent = nullptr) : TestPage(nullptr, parent) { }
+ TestPage(QWebEngineProfile *profile, QObject *parent = nullptr) : QWebEnginePage(profile, parent) {
+ connect(this, &QWebEnginePage::loadStarted, [this] () { signalsOrder.append(LoadStarted); });
+ connect(this, &QWebEnginePage::loadProgress, [this] (int p) { loadProgress.append(p); });
+ connect(this, &QWebEnginePage::loadFinished, [this] (bool r) { signalsOrder.append(r ? LoadSucceeded : LoadFailed); });
+ connect(this, &QWebEnginePage::loadingChanged, [this] (const QWebEngineLoadingInfo &i) { loadingInfos.append(i); });
+ }
+ ~TestPage() { Q_ASSERT(signalsOrder.size() == loadingInfos.size()); }
+
+ void reset()
+ {
+ blacklist.clear();
+ navigationRequestCount = 0;
+ signalsOrder.clear();
+ loadProgress.clear();
+ loadingInfos.clear();
+ }
+
+protected:
+ bool acceptNavigationRequest(const QUrl &url, NavigationType, bool) override
+ {
+ ++navigationRequestCount;
+ return !blacklist.contains(url);
+ }
+};
+
class tst_LoadSignals : public QObject
{
Q_OBJECT
@@ -48,32 +70,59 @@ private Q_SLOTS:
void monotonicity();
void loadStartedAndFinishedCount_data();
void loadStartedAndFinishedCount();
- void secondLoadForError_WhenErrorPageEnabled_data();
- void secondLoadForError_WhenErrorPageEnabled();
+ void loadStartedAndFinishedCountClick_data();
+ void loadStartedAndFinishedCountClick();
+ void rejectNavigationRequest_data();
+ void rejectNavigationRequest();
void loadAfterInPageNavigation_qtbug66869();
- void fileDownloadDoesNotTriggerLoadSignals_qtbug66661();
+ void fileDownload();
+ void numberOfStartedAndFinishedSignalsIsSame_data();
+ void numberOfStartedAndFinishedSignalsIsSame();
+ void loadFinishedAfterNotFoundError_data();
+ void loadFinishedAfterNotFoundError();
+ void errorPageTriggered_data();
+ void errorPageTriggered();
private:
+ void clickLink(QPoint linkPos);
+
QWebEngineProfile profile;
- QWebEnginePage page{&profile};
+ TestPage page{&profile};
QWebEngineView view;
QSignalSpy loadStartedSpy{&page, &QWebEnginePage::loadStarted};
- QSignalSpy loadProgressSpy{&page, &QWebEnginePage::loadProgress};
QSignalSpy loadFinishedSpy{&page, &QWebEnginePage::loadFinished};
+ void resetSpies() {
+ loadStartedSpy.clear();
+ loadFinishedSpy.clear();
+ }
};
void tst_LoadSignals::initTestCase()
{
view.setPage(&page);
- view.resize(1024,768);
+ view.resize(640, 480);
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
}
void tst_LoadSignals::init()
{
- loadStartedSpy.clear();
- loadProgressSpy.clear();
- loadFinishedSpy.clear();
+ // Reset content
+ if (!view.url().isEmpty()) {
+ loadFinishedSpy.clear();
+ view.load(QUrl("about:blank"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ }
+ resetSpies();
+ page.reset();
+}
+
+void tst_LoadSignals::clickLink(QPoint linkPos)
+{
+ // Simulate left-clicking on link.
+ QTRY_VERIFY(view.focusProxy());
+ QWidget *renderWidget = view.focusProxy();
+ QTest::mouseClick(renderWidget, Qt::LeftButton, {}, linkPos);
}
/**
@@ -82,31 +131,137 @@ void tst_LoadSignals::init()
void tst_LoadSignals::loadStartedAndFinishedCount_data()
{
QTest::addColumn<QUrl>("url");
- QTest::addColumn<int>("expectedLoadCount");
- QTest::newRow("Normal") << QUrl("qrc:///resources/page1.html") << 1;
- QTest::newRow("WithAnchor") << QUrl("qrc:///resources/page2.html#anchor") << 1;
-
- // In this case, we get an unexpected additional loadStarted, but no corresponding
- // loadFinished, so expectedLoadCount=2 would also not work. See also QTBUG-65223
- QTest::newRow("WithAnchorClickedFromJS") << QUrl("qrc:///resources/page3.html") << 1;
+ QTest::addColumn<QList<int>>("expectedSignals");
+ QTest::newRow("Simple") << QUrl("qrc:///resources/page1.html") << SignalsOrderOnce;
+ QTest::newRow("SimpleWithAnchor") << QUrl("qrc:///resources/page2.html#anchor") << SignalsOrderOnce;
+ QTest::newRow("SamePageImmediate") << QUrl("qrc:///resources/page5.html") << SignalsOrderOnce;
+ QTest::newRow("SamePageDeferred") << QUrl("qrc:///resources/page3.html") << SignalsOrderOnce;
+ QTest::newRow("OtherPageImmediate") << QUrl("qrc:///resources/page6.html") << SignalsOrderOnce;
+ QTest::newRow("OtherPageDeferred") << QUrl("qrc:///resources/page7.html") << SignalsOrderTwice;
+ QTest::newRow("SamePageImmediateJS") << QUrl("qrc:///resources/page8.html") << SignalsOrderOnce;
}
void tst_LoadSignals::loadStartedAndFinishedCount()
{
QFETCH(QUrl, url);
- QFETCH(int, expectedLoadCount);
+ QFETCH(QList<int>, expectedSignals);
view.load(url);
+
+ int expectedLoadCount = expectedSignals.size() / 2;
+ QTRY_COMPARE(loadStartedSpy.size(), expectedLoadCount);
QTRY_COMPARE(loadFinishedSpy.size(), expectedLoadCount);
+
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != expectedLoadCount || loadFinishedSpy.size() != expectedLoadCount, 1000, 100);
+
+ // No further signals should have occurred within this time and expected number of signals is preserved
+ QCOMPARE(loadStartedSpy.size(), expectedLoadCount);
+ QCOMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.signalsOrder, expectedSignals);
+ QCOMPARE(page.signalsOrder.size(), page.loadingInfos.size());
+ for (int i = 0; i < page.signalsOrder.size(); ++i)
+ QCOMPARE(page.signalsOrder[i], page.loadingInfos[i].status());
+}
+
+/**
+ * Load a URL, then simulate a click to load a different URL.
+ */
+void tst_LoadSignals::loadStartedAndFinishedCountClick_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<int>("numberOfSignals");
+ QTest::newRow("SamePage") << QUrl("qrc:///resources/page2.html") << 0; // in-page navigation to anchor shouldn't emit anything
+ QTest::newRow("OtherPage") << QUrl("qrc:///resources/page1.html") << 1;
+}
+
+void tst_LoadSignals::loadStartedAndFinishedCountClick()
+{
+ QFETCH(QUrl, url);
+ QFETCH(int, numberOfSignals);
+
+ view.load(url);
+ QTRY_COMPARE(loadStartedSpy.size(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QVERIFY(loadFinishedSpy[0][0].toBool());
+ resetSpies();
+
+ clickLink(QPoint(10, 10));
+ if (numberOfSignals > 0) {
+ QTRY_COMPARE(loadStartedSpy.size(), numberOfSignals);
+ QTRY_COMPARE(loadFinishedSpy.size(), numberOfSignals);
+ QVERIFY(loadFinishedSpy[0][0].toBool());
+ }
+
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != numberOfSignals || loadFinishedSpy.size() != numberOfSignals, 1000, 100);
+
+ // No further loadStarted should have occurred within this time
+ QCOMPARE(loadStartedSpy.size(), numberOfSignals);
+ QCOMPARE(loadFinishedSpy.size(), numberOfSignals);
+ QCOMPARE(page.signalsOrder, numberOfSignals > 0 ? SignalsOrderTwice : SignalsOrderOnce);
+}
+
+void tst_LoadSignals::rejectNavigationRequest_data()
+{
+ QTest::addColumn<QUrl>("initialUrl");
+ QTest::addColumn<QUrl>("rejectedUrl");
+ QTest::addColumn<int>("expectedNavigations");
+ QTest::addColumn<QList<int>>("expectedSignals");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<QWebEngineLoadingInfo::ErrorDomain>("errorDomain");
+ QTest::newRow("Simple")
+ << QUrl("qrc:///resources/page1.html")
+ << QUrl("qrc:///resources/page1.html")
+ << 1 << SignalsOrderOnceFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
+ QTest::newRow("SamePageImmediate")
+ << QUrl("qrc:///resources/page5.html")
+ << QUrl("qrc:///resources/page5.html#anchor")
+ << 1 << SignalsOrderOnce << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("SamePageDeferred")
+ << QUrl("qrc:///resources/page3.html")
+ << QUrl("qrc:///resources/page3.html#anchor")
+ << 1 << SignalsOrderOnce << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("OtherPageImmediate")
+ << QUrl("qrc:///resources/page6.html")
+ << QUrl("qrc:///resources/page2.html#anchor")
+ << 2 << SignalsOrderOnceFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
+ QTest::newRow("OtherPageDeferred")
+ << QUrl("qrc:///resources/page7.html")
+ << QUrl("qrc:///resources/page2.html#anchor")
+ << 2 << SignalsOrderTwiceWithFailure << -3 << QWebEngineLoadingInfo::InternalErrorDomain;
+}
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy.size() != expectedLoadCount)
- || (loadFinishedSpy.size() != expectedLoadCount), 10000, 100);
+/**
+ * Returning false from acceptNavigationRequest means that the load
+ * fails, not that the load never starts.
+ *
+ * See QTBUG-75185.
+ */
+void tst_LoadSignals::rejectNavigationRequest()
+{
+ QFETCH(QUrl, initialUrl);
+ QFETCH(QUrl, rejectedUrl);
+ QFETCH(int, expectedNavigations);
+ QFETCH(QList<int>, expectedSignals);
+ QFETCH(int, errorCode);
+ QFETCH(QWebEngineLoadingInfo::ErrorDomain, errorDomain);
+
+ page.blacklist.insert(rejectedUrl);
+ page.load(initialUrl);
+ QTRY_COMPARE(page.navigationRequestCount, expectedNavigations);
+ int expectedLoadCount = expectedSignals.size() / 2;
+ QTRY_COMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.signalsOrder, expectedSignals);
+
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != expectedLoadCount || loadFinishedSpy.size() != expectedLoadCount, 1000, 100);
// No further loadStarted should have occurred within this time
QCOMPARE(loadStartedSpy.size(), expectedLoadCount);
QCOMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.loadingInfos.last().errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos.last().errorDomain(), errorDomain);
}
/**
@@ -115,63 +270,29 @@ void tst_LoadSignals::loadStartedAndFinishedCount()
void tst_LoadSignals::monotonicity()
{
HttpServer server;
- server.setResourceDirs({ TESTS_SHARED_DATA_DIR });
+ server.setResourceDirs({ server.sharedDataDir() });
connect(&server, &HttpServer::newRequest, [] (HttpReqRep *) {
QTest::qWait(250); // just add delay to trigger some progress for every sub resource
});
QVERIFY(server.start());
view.load(server.url("/loadprogress/main.html"));
- QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 10000);
QVERIFY(loadFinishedSpy[0][0].toBool());
+ QVERIFY(page.loadProgress.size() >= 3);
// first loadProgress should have 0% progress
- QCOMPARE(loadProgressSpy.takeFirst()[0].toInt(), 0);
+ QCOMPARE(page.loadProgress.first(), 0);
// every loadProgress should have more progress than the one before
- int progress = 0;
- for (const auto &item : loadProgressSpy) {
- QVERIFY(progress < item[0].toInt());
- progress = item[0].toInt();
+ int progress = -1;
+ for (int p : page.loadProgress) {
+ QVERIFY(progress < p);
+ progress = p;
}
// last loadProgress should have 100% progress
- QCOMPARE(loadProgressSpy.last()[0].toInt(), 100);
-}
-
-/**
- * Test that we get a second loadStarted and loadFinished signal
- * for error-pages (unless error-pages are disabled)
- */
-void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled_data()
-{
- QTest::addColumn<bool>("enabled");
- // in this case, we get no second loadStarted and loadFinished, although we had
- // agreed on making the navigation to an error page an individual load
- QTest::newRow("ErrorPageEnabled") << true;
- QTest::newRow("ErrorPageDisabled") << false;
-}
-
-void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled()
-{
- QFETCH(bool, enabled);
- view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, enabled);
- int expectedLoadCount = (enabled ? 2 : 1);
-
- // RFC 2606 guarantees that this will never become a valid domain
- view.load(QUrl("http://nonexistent.invalid"));
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), expectedLoadCount, 10000);
- QVERIFY(!loadFinishedSpy[0][0].toBool());
- if (enabled)
- QVERIFY(loadFinishedSpy[1][0].toBool());
-
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy.size() != expectedLoadCount)
- || (loadFinishedSpy.size() != expectedLoadCount), 10000, 100);
-
- // No further loadStarted should have occurred within this time
- QCOMPARE(loadStartedSpy.size(), expectedLoadCount);
- QCOMPARE(loadFinishedSpy.size(), expectedLoadCount);
+ QCOMPARE(page.loadProgress.last(), 100);
}
/**
@@ -185,27 +306,17 @@ void tst_LoadSignals::loadAfterInPageNavigation_qtbug66869()
QVERIFY(loadFinishedSpy[0][0].toBool());
// page3 does an in-page navigation after 500ms
- QTest::qWait(2000);
- loadFinishedSpy.clear();
- loadProgressSpy.clear();
- loadStartedSpy.clear();
+ QTRY_COMPARE(view.url(), QUrl("qrc:///resources/page3.html#anchor"));
// second load
view.load(QUrl("qrc:///resources/page1.html"));
- QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QTRY_COMPARE(loadFinishedSpy.size(), 2);
QVERIFY(loadFinishedSpy[0][0].toBool());
// loadStarted and loadFinished should have been signalled
- QCOMPARE(loadStartedSpy.size(), 1);
-
- // reminder that we still need to solve the core issue
- QFAIL("https://codereview.qt-project.org/#/c/222112/ only hides the symptom, the core issue still needs to be solved");
+ QCOMPARE(loadStartedSpy.size(), 2);
}
-/**
- * Test that file-downloads don't trigger loadStarted or loadFinished signals.
- * See QTBUG-66661
- */
-void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
+void tst_LoadSignals::fileDownload()
{
view.load(QUrl("qrc:///resources/page4.html"));
QTRY_COMPARE(loadFinishedSpy.size(), 1);
@@ -214,12 +325,12 @@ void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
// allow the download
QTemporaryDir tempDir;
QVERIFY(tempDir.isValid());
- QWebEngineDownloadItem::DownloadState downloadState = QWebEngineDownloadItem::DownloadRequested;
+ QWebEngineDownloadRequest::DownloadState downloadState = QWebEngineDownloadRequest::DownloadRequested;
ScopedConnection sc1 =
connect(&profile, &QWebEngineProfile::downloadRequested,
- [&downloadState, &tempDir](QWebEngineDownloadItem *item) {
- connect(item, &QWebEngineDownloadItem::stateChanged,
- [&downloadState](QWebEngineDownloadItem::DownloadState newState) {
+ [&downloadState, &tempDir](QWebEngineDownloadRequest *item) {
+ connect(item, &QWebEngineDownloadRequest::stateChanged,
+ [&downloadState](QWebEngineDownloadRequest::DownloadState newState) {
downloadState = newState;
});
item->setDownloadDirectory(tempDir.path());
@@ -227,20 +338,198 @@ void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
});
// trigger the download link that becomes focused on page4
- QTest::qWait(1000);
QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
- // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs)
- QTRY_LOOP_IMPL((loadStartedSpy.size() != 1)
- || (loadFinishedSpy.size() != 1), 10000, 100);
-
// Download must have occurred
- QTRY_COMPARE(downloadState, QWebEngineDownloadItem::DownloadCompleted);
+ QTRY_COMPARE(downloadState, QWebEngineDownloadRequest::DownloadCompleted);
+ QTRY_COMPARE(loadFinishedSpy.size() + loadStartedSpy.size(), 4);
- // No further loadStarted should have occurred within this time
- QCOMPARE(loadStartedSpy.size(), 1);
+ // verify no more signals is emitted by waiting for another loadStarted or loadFinished
+ QTRY_LOOP_IMPL(loadStartedSpy.size() != 2 || loadFinishedSpy.size() != 2, 1000, 100);
+
+ QCOMPARE(page.signalsOrder, SignalsOrderTwiceWithFailure);
+ QCOMPARE(page.loadingInfos[3].errorCode(), -3);
+ QCOMPARE(page.loadingInfos[3].errorDomain(), QWebEngineLoadingInfo::InternalErrorDomain);
+}
+
+void tst_LoadSignals::numberOfStartedAndFinishedSignalsIsSame_data()
+{
+ QTest::addColumn<bool>("imageFromServer");
+ QTest::addColumn<QString>("imageResourceUrl");
+ // triggers these calls in delegate internally:
+ // just two ordered triples DidStartNavigation/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("no_image_resource") << false << "";
+ // out of order: DidStartNavigation/DidFinishNavigation/DidStartNavigation/DidFailLoad/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("with_invalid_image") << false << "https://non.existent.locahost/image.png";
+ // out of order: DidStartNavigation/DidFinishNavigation/DidStartNavigation/DidFinishLoad/DidFinishNavigation/DidFinishLoad
+ QTest::newRow("with_server_image") << true << "";
+}
+
+void tst_LoadSignals::numberOfStartedAndFinishedSignalsIsSame()
+{
+ QFETCH(bool, imageFromServer);
+ QFETCH(QString, imageResourceUrl);
+
+ HttpServer server;
+ server.setResourceDirs({ server.sharedDataDir() });
+ QVERIFY(server.start());
+
+ QUrl serverImage = server.url("/hedgehog.png");
+ QString imageUrl(!imageFromServer && imageResourceUrl.isEmpty()
+ ? "" : (imageFromServer ? serverImage.toEncoded() : imageResourceUrl));
+
+ auto html = "<html><head><link rel='icon' href='data:,'></head><body>"
+ "%1" "<form method='GET' name='hiddenform' action='qrc:///resources/page1.html' />"
+ "<script language='javascript'>document.forms[0].submit();</script>"
+ "</body></html>";
+ view.page()->setHtml(QString(html).arg(imageUrl.isEmpty() ? "" : "<img src='" + imageUrl + "'>"));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+
+ resetSpies();
+ QTRY_LOOP_IMPL(loadStartedSpy.size() || loadFinishedSpy.size(), 1000, 100);
+ QCOMPARE(page.signalsOrder, SignalsOrderOnce);
+ QCOMPARE(page.loadingInfos[1].errorCode(), 200);
+ QCOMPARE(page.loadingInfos[1].errorDomain(), QWebEngineLoadingInfo::HttpStatusCodeDomain);
+}
+
+void tst_LoadSignals::loadFinishedAfterNotFoundError_data()
+{
+ QTest::addColumn<bool>("rfcInvalid");
+ QTest::addColumn<bool>("withServer");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<int>("errorDomain");
+ QTest::addRow("rfc_invalid") << true << false << -105 << int(QWebEngineLoadingInfo::ConnectionErrorDomain);
+ QTest::addRow("non_existent") << false << false << -105 << int(QWebEngineLoadingInfo::ConnectionErrorDomain);
+ QTest::addRow("server_404") << false << true << 404 << int(QWebEngineLoadingInfo::HttpStatusCodeDomain);
+}
+
+void tst_LoadSignals::loadFinishedAfterNotFoundError()
+{
+ QFETCH(bool, rfcInvalid);
+ QFETCH(bool, withServer);
+ QFETCH(int, errorCode);
+ QFETCH(int, errorDomain);
+
+ QScopedPointer<HttpServer> server;
+ if (withServer) {
+ server.reset(new HttpServer);
+ QVERIFY(server->start());
+ }
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ auto url = server
+ ? server->url("/not-found-page.html")
+ : QUrl(rfcInvalid ? "http://some.invalid" : "http://non.existent/url");
+ view.load(url);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 20000);
+ QVERIFY(!loadFinishedSpy.at(0).at(0).toBool());
+ QCOMPARE(toPlainTextSync(view.page()), QString());
QCOMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadStartedSpy.size(), 1);
+ QVERIFY(std::is_sorted(page.loadProgress.begin(), page.loadProgress.end()));
+ page.loadProgress.clear();
+
+ { auto &&loadStart = page.loadingInfos[0], &&loadFinish = page.loadingInfos[1];
+ QCOMPARE(loadStart.status(), QWebEngineLoadingInfo::LoadStartedStatus);
+ QCOMPARE(loadStart.isErrorPage(), false);
+ QCOMPARE(loadStart.errorCode(), 0);
+ QCOMPARE(loadStart.errorDomain(), QWebEngineLoadingInfo::NoErrorDomain);
+ QCOMPARE(loadStart.errorString(), QString());
+ QCOMPARE(loadFinish.status(), QWebEngineLoadingInfo::LoadFailedStatus);
+ QCOMPARE(loadFinish.isErrorPage(), false);
+ QCOMPARE(loadFinish.errorCode(), errorCode);
+ QCOMPARE(loadFinish.errorDomain(), errorDomain);
+ QVERIFY(!loadFinish.errorString().isEmpty());
+ }
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
+ url = server
+ ? server->url("/another-missing-one.html")
+ : QUrl(rfcInvalid ? "http://some.other.invalid" : "http://another.non.existent/url");
+ view.load(url);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 20000);
+ QVERIFY(!loadFinishedSpy.at(1).at(0).toBool());
+ QCOMPARE(loadStartedSpy.size(), 2);
+
+ QEXPECT_FAIL("", "No more loads (like separate load for error pages) are expected", Continue);
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 3, 1000);
+ QCOMPARE(loadStartedSpy.size(), 2);
+ QVERIFY(std::is_sorted(page.loadProgress.begin(), page.loadProgress.end()));
+
+ { auto &&loadStart = page.loadingInfos[2], &&loadFinish = page.loadingInfos[3];
+ QCOMPARE(loadStart.status(), QWebEngineLoadingInfo::LoadStartedStatus);
+ QCOMPARE(loadStart.isErrorPage(), false);
+ QCOMPARE(loadStart.errorCode(), 0);
+ QCOMPARE(loadStart.errorDomain(), QWebEngineLoadingInfo::NoErrorDomain);
+ QCOMPARE(loadStart.errorString(), QString());
+ QCOMPARE(loadFinish.status(), QWebEngineLoadingInfo::LoadFailedStatus);
+ QCOMPARE(loadFinish.isErrorPage(), true);
+ QCOMPARE(loadFinish.errorCode(), errorCode);
+ QCOMPARE(loadFinish.errorDomain(), errorDomain);
+ QVERIFY(!loadFinish.errorString().isEmpty());
+ }
+}
+
+void tst_LoadSignals::errorPageTriggered_data()
+{
+ QTest::addColumn<QString>("urlPath");
+ QTest::addColumn<bool>("loadSucceed");
+ QTest::addColumn<bool>("triggersErrorPage");
+ QTest::addColumn<int>("errorCode");
+ QTest::addColumn<QWebEngineLoadingInfo::ErrorDomain>("errorDomain");
+ QTest::newRow("/content/200") << QStringLiteral("/content/200") << true << false << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/empty/200") << QStringLiteral("/content/200") << true << false << 200 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/content/404") << QStringLiteral("/content/404") << false << false << 404 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+ QTest::newRow("/empty/404") << QStringLiteral("/empty/404") << false << true << 404 << QWebEngineLoadingInfo::HttpStatusCodeDomain;
+}
+
+void tst_LoadSignals::errorPageTriggered()
+{
+ HttpServer server;
+ connect(&server, &HttpServer::newRequest, [] (HttpReqRep *rr) {
+ QList<QByteArray> parts = rr->requestPath().split('/');
+ if (parts.size() != 3) {
+ // For example, /favicon.ico
+ rr->sendResponse(404);
+ return;
+ }
+ bool isDocumentEmpty = (parts[1] == "empty");
+ int httpStatusCode = parts[2].toInt();
+
+ rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("text/html"));
+ if (!isDocumentEmpty) {
+ rr->setResponseBody(QByteArrayLiteral("<html></html>"));
+ }
+ rr->sendResponse(httpStatusCode);
+ });
+ QVERIFY(server.start());
+
+ QFETCH(QString, urlPath);
+ QFETCH(bool, loadSucceed);
+ QFETCH(bool, triggersErrorPage);
+ QFETCH(int, errorCode);
+ QFETCH(QWebEngineLoadingInfo::ErrorDomain, errorDomain);
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
+ view.load(server.url(urlPath));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadFinishedSpy[0][0].toBool(), loadSucceed);
+ if (triggersErrorPage)
+ QVERIFY(toPlainTextSync(view.page()).contains("HTTP ERROR 404"));
+ else
+ QVERIFY(toPlainTextSync(view.page()).isEmpty());
+ QCOMPARE(page.loadingInfos[1].errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos[1].errorDomain(), errorDomain);
+ loadFinishedSpy.clear();
+
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ view.load(server.url(urlPath));
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
+ QCOMPARE(loadFinishedSpy[0][0].toBool(), loadSucceed);
+ QVERIFY(toPlainTextSync(view.page()).isEmpty());
+ QCOMPARE(page.loadingInfos[3].errorCode(), errorCode);
+ QCOMPARE(page.loadingInfos[3].errorDomain(), errorDomain);
+ loadFinishedSpy.clear();
}
QTEST_MAIN(tst_LoadSignals)