blob: 20e5fbf0dab99c925b211f870e109a6e71ae8279 [file] [log] [blame]
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include <QtTest/QtTest>
#include "../util.h"
#include "qdebug.h"
#include "qwebenginepage.h"
#include "qwebengineprofile.h"
#include "qwebenginesettings.h"
#include "qwebengineview.h"
class tst_LoadSignals : public QObject
{
Q_OBJECT
public:
tst_LoadSignals();
virtual ~tst_LoadSignals();
public Q_SLOTS:
void initTestCase();
void init();
void cleanup();
private Q_SLOTS:
void monotonicity();
void loadStartedAndFinishedCount_data();
void loadStartedAndFinishedCount();
void secondLoadForError_WhenErrorPageEnabled_data();
void secondLoadForError_WhenErrorPageEnabled();
void loadAfterInPageNavigation_qtbug66869();
void fileDownloadDoesNotTriggerLoadSignals_qtbug66661();
private:
QWebEngineView* view;
QScopedPointer<QSignalSpy> loadStartedSpy;
QScopedPointer<QSignalSpy> loadProgressSpy;
QScopedPointer<QSignalSpy> loadFinishedSpy;
};
tst_LoadSignals::tst_LoadSignals()
{
}
tst_LoadSignals::~tst_LoadSignals()
{
}
void tst_LoadSignals::initTestCase()
{
}
void tst_LoadSignals::init()
{
view = new QWebEngineView();
view->resize(1024,768);
view->show();
loadStartedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadStarted));
loadProgressSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadProgress));
loadFinishedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadFinished));
}
void tst_LoadSignals::cleanup()
{
loadFinishedSpy.reset();
loadProgressSpy.reset();
loadStartedSpy.reset();
delete view;
}
/**
* Test that we get the expected number of loadStarted and loadFinished signals
*/
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;
}
void tst_LoadSignals::loadStartedAndFinishedCount()
{
QFETCH(QUrl, url);
QFETCH(int, expectedLoadCount);
view->load(url);
QTRY_COMPARE(loadFinishedSpy->size(), expectedLoadCount);
bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(loadSucceeded);
// 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);
}
/**
* Test monotonicity of loadProgress signals
*/
void tst_LoadSignals::monotonicity()
{
view->load(QUrl("qrc:///resources/page1.html"));
QTRY_COMPARE(loadFinishedSpy->size(), 1);
bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(loadSucceeded);
// first loadProgress should have 0% progress
QCOMPARE(loadProgressSpy->first()[0].toInt(), 0);
// every loadProgress should have at least as much progress as the one before
int progress = 0;
for (auto item : *loadProgressSpy) {
QVERIFY(item[0].toInt() >= progress);
progress = item[0].toInt();
}
// 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);
bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(!loadSucceeded);
if (enabled) {
bool errorPageLoadSucceeded = (*loadFinishedSpy)[1][0].toBool();
QVERIFY(errorPageLoadSucceeded);
}
// 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);
}
/**
* Test that a second load after an in-page navigation receives its expected loadStarted and
* loadFinished signal.
*/
void tst_LoadSignals::loadAfterInPageNavigation_qtbug66869()
{
view->load(QUrl("qrc:///resources/page3.html"));
QTRY_COMPARE(loadFinishedSpy->size(), 1);
bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(loadSucceeded);
// page3 does an in-page navigation after 500ms
QTest::qWait(2000);
loadFinishedSpy->clear();
loadProgressSpy->clear();
loadStartedSpy->clear();
// second load
view->load(QUrl("qrc:///resources/page1.html"));
QTRY_COMPARE(loadFinishedSpy->size(), 1);
loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(loadSucceeded);
// 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");
}
/**
* Test that file-downloads don't trigger loadStarted or loadFinished signals.
* See QTBUG-66661
*/
void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
{
view->load(QUrl("qrc:///resources/page4.html"));
QTRY_COMPARE(loadFinishedSpy->size(), 1);
bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool();
QVERIFY(loadSucceeded);
// allow the download
QTemporaryDir tempDir;
QWebEngineDownloadItem::DownloadState downloadState = QWebEngineDownloadItem::DownloadRequested;
connect(view->page()->profile(), &QWebEngineProfile::downloadRequested,
[&downloadState, &tempDir](QWebEngineDownloadItem* item){
connect(item, &QWebEngineDownloadItem::stateChanged, [&downloadState](QWebEngineDownloadItem::DownloadState newState){
downloadState = newState;
});
item->setDownloadDirectory(tempDir.filePath(QFileInfo(item->path()).path()));
item->setDownloadFileName(QFileInfo(item->path()).fileName());
item->accept();
});
// 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);
// No further loadStarted should have occurred within this time
QCOMPARE(loadStartedSpy->size(), 1);
QCOMPARE(loadFinishedSpy->size(), 1);
}
QTEST_MAIN(tst_LoadSignals)
#include "tst_loadsignals.moc"