blob: 224814f7e5ff9bb8acdac32ce6d2567b0e21cee4 [file] [log] [blame]
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QScopedPointer>
#include <QtQml/QQmlEngine>
#include <QtTest/QtTest>
#include <QQuickWebEngineProfile>
#include <QtWebEngine/private/qquickwebengineview_p.h>
#define INSPECTOR_SERVER_PORT "23654"
static const QUrl s_inspectorServerHttpBaseUrl("http://localhost:" INSPECTOR_SERVER_PORT);
class tst_InspectorServer : public QObject {
Q_OBJECT
public:
tst_InspectorServer();
private Q_SLOTS:
void init();
void cleanup();
void testPageList();
void testRemoteDebuggingMessage();
void openRemoteDebuggingSession();
private:
void prepareWebViewComponent();
inline QQuickWebEngineView* newWebView();
inline QQuickWebEngineView* webView() const;
QJsonArray fetchPageList() const;
QScopedPointer<QQuickWebEngineView> m_webView;
QScopedPointer<QQmlComponent> m_component;
};
tst_InspectorServer::tst_InspectorServer()
{
qputenv("QTWEBENGINE_REMOTE_DEBUGGING", INSPECTOR_SERVER_PORT);
QtWebEngine::initialize();
QQuickWebEngineProfile::defaultProfile()->setOffTheRecord(true);
prepareWebViewComponent();
}
void tst_InspectorServer::prepareWebViewComponent()
{
static QQmlEngine* engine = new QQmlEngine(this);
engine->addImportPath(QString::fromUtf8(IMPORT_DIR));
m_component.reset(new QQmlComponent(engine, this));
m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n"
"import QtWebEngine 1.2\n"
"WebEngineView { }")
, QUrl());
}
QQuickWebEngineView* tst_InspectorServer::newWebView()
{
QObject* viewInstance = m_component->create();
return qobject_cast<QQuickWebEngineView*>(viewInstance);
}
void tst_InspectorServer::init()
{
m_webView.reset(newWebView());
}
void tst_InspectorServer::cleanup()
{
m_webView.reset();
}
inline QQuickWebEngineView* tst_InspectorServer::webView() const
{
return m_webView.data();
}
QJsonArray tst_InspectorServer::fetchPageList() const
{
QNetworkAccessManager qnam;
QScopedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(s_inspectorServerHttpBaseUrl.resolved(QUrl("json/list")))));
QSignalSpy(reply.data(), SIGNAL(finished())).wait();
return QJsonDocument::fromJson(reply->readAll()).array();
}
void tst_InspectorServer::testPageList()
{
const QUrl testPageUrl = QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "/html/basic_page.html"));
QSignalSpy loadSpy(webView(), SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*)));
webView()->setUrl(testPageUrl);
QTRY_VERIFY(loadSpy.size() && !webView()->isLoading());
// Our page has developerExtrasEnabled and should be the only one in the list.
QJsonArray pageList = fetchPageList();
QCOMPARE(pageList.size(), 1);
QCOMPARE(testPageUrl.toString(), pageList.at(0).toObject().value("url").toString());
}
void tst_InspectorServer::testRemoteDebuggingMessage()
{
QJsonArray pageList = fetchPageList();
QCOMPARE(pageList.size(), 1);
QVERIFY(pageList.at(0).toObject().contains("webSocketDebuggerUrl"));
// Test sending a raw remote debugging message through our web socket server.
// For this specific message see: http://code.google.com/chrome/devtools/docs/protocol/tot/runtime.html#command-evaluate
QLatin1String jsExpression("2 + 2");
QLatin1String jsExpressionResult("4");
QScopedPointer<QQuickWebEngineView> webSocketQueryWebView(newWebView());
webSocketQueryWebView->loadHtml(QString(
"<script type=\"text/javascript\">\n"
"var socket = new WebSocket('%1');\n"
"socket.onmessage = function(message) {\n"
"var response = JSON.parse(message.data);\n"
"if (response.id === 1)\n"
"document.title = response.result.result.value;\n"
"}\n"
"socket.onopen = function() {\n"
"socket.send('{\"id\": 1, \"method\": \"Runtime.evaluate\", \"params\": {\"expression\": \"%2\" } }');\n"
"}\n"
"</script>")
.arg(pageList.at(0).toObject().value("webSocketDebuggerUrl").toString())
.arg(jsExpression));
QTRY_COMPARE(webSocketQueryWebView->title(), jsExpressionResult);
}
void tst_InspectorServer::openRemoteDebuggingSession()
{
QJsonArray pageList = fetchPageList();
QCOMPARE(pageList.size(), 1);
QVERIFY(pageList.at(0).toObject().contains("devtoolsFrontendUrl"));
QScopedPointer<QQuickWebEngineView> inspectorWebView(newWebView());
inspectorWebView->setUrl(s_inspectorServerHttpBaseUrl.resolved(QUrl(pageList.at(0).toObject().value("devtoolsFrontendUrl").toString())));
// To test the whole pipeline this exploits a behavior of the inspector front-end which won't provide any title unless the
// debugging session was established correctly through web socket.
// So this test case will fail if:
// - The page list didn't return a valid inspector URL
// - Or the front-end couldn't be loaded through the inspector HTTP server
// - Or the web socket connection couldn't be established between the front-end and the page through the inspector server
QTRY_VERIFY_WITH_TIMEOUT(inspectorWebView->title().startsWith("DevTools -"), 30000);
}
QTEST_MAIN(tst_InspectorServer)
#include "tst_inspectorserver.moc"