1/* 2 Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18*/ 19 20#include "../testwindow.h" 21#include "../util.h" 22 23#include <QNetworkAccessManager> 24#include <QNetworkReply> 25#include <QNetworkRequest> 26#include <QScopedPointer> 27#include <QtQml/QQmlEngine> 28#include <QtTest/QtTest> 29#include <private/qquickwebview_p.h> 30#include <private/qwebpreferences_p.h> 31 32#define INSPECTOR_SERVER_PORT "23654" 33static const QUrl s_inspectorServerHttpBaseUrl("http://localhost:" INSPECTOR_SERVER_PORT); 34static const QUrl s_inspectorServerWebSocketBaseUrl("ws://localhost:" INSPECTOR_SERVER_PORT); 35 36class tst_InspectorServer : public QObject { 37 Q_OBJECT 38public: 39 tst_InspectorServer(); 40 41private Q_SLOTS: 42 void init(); 43 void cleanup(); 44 45 void testPageList(); 46 void testRemoteDebuggingMessage(); 47 void openRemoteDebuggingSession(); 48private: 49 void prepareWebViewComponent(); 50 inline QQuickWebView* newWebView(); 51 inline QQuickWebView* webView() const; 52 QJsonArray fetchPageList() const; 53 QScopedPointer<TestWindow> m_window; 54 QScopedPointer<QQmlComponent> m_component; 55}; 56 57tst_InspectorServer::tst_InspectorServer() 58{ 59 qputenv("QTWEBKIT_INSPECTOR_SERVER", INSPECTOR_SERVER_PORT); 60 addQtWebProcessToPath(); 61 prepareWebViewComponent(); 62} 63 64void tst_InspectorServer::prepareWebViewComponent() 65{ 66 static QQmlEngine* engine = new QQmlEngine(this); 67 engine->addImportPath(QString::fromUtf8(IMPORT_DIR)); 68 69 m_component.reset(new QQmlComponent(engine, this)); 70 71 m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n" 72 "import QtWebKit 3.0\n" 73 "WebView {}") 74 , QUrl()); 75} 76 77QQuickWebView* tst_InspectorServer::newWebView() 78{ 79 QObject* viewInstance = m_component->create(); 80 81 return qobject_cast<QQuickWebView*>(viewInstance); 82} 83 84void tst_InspectorServer::init() 85{ 86 m_window.reset(new TestWindow(newWebView())); 87 webView()->experimental()->preferences()->setDeveloperExtrasEnabled(true); 88} 89 90void tst_InspectorServer::cleanup() 91{ 92 m_window.reset(); 93} 94 95inline QQuickWebView* tst_InspectorServer::webView() const 96{ 97 return static_cast<QQuickWebView*>(m_window->webView.data()); 98} 99 100QJsonArray tst_InspectorServer::fetchPageList() const 101{ 102 QNetworkAccessManager qnam; 103 QScopedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(s_inspectorServerHttpBaseUrl.resolved(QUrl("pagelist.json"))))); 104 waitForSignal(reply.data(), SIGNAL(finished())); 105 return QJsonDocument::fromJson(reply->readAll()).array(); 106} 107 108void tst_InspectorServer::testPageList() 109{ 110 QUrl testPageUrl = QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "/html/basic_page.html")); 111 LoadStartedCatcher catcher(webView()); 112 webView()->setUrl(testPageUrl); 113 waitForSignal(&catcher, SIGNAL(finished())); 114 115 // Our page has developerExtrasEnabled and should be the only one in the list. 116 QJsonArray pageList = fetchPageList(); 117 QCOMPARE(pageList.size(), 1); 118 QCOMPARE(testPageUrl.toString(), pageList.at(0).toObject().value("url").toString()); 119} 120 121void tst_InspectorServer::testRemoteDebuggingMessage() 122{ 123 QJsonArray pageList = fetchPageList(); 124 QCOMPARE(pageList.size(), 1); 125 126 // Test sending a raw remote debugging message through our web socket server. 127 // For this specific message see: http://code.google.com/chrome/devtools/docs/protocol/tot/runtime.html#command-evaluate 128 QLatin1String jsExpression("2 + 2"); 129 QLatin1String jsExpressionResult("4"); 130 QScopedPointer<QQuickWebView> webSocketQueryWebView(newWebView()); 131 webSocketQueryWebView->loadHtml(QString( 132 "<script type=\"text/javascript\">\n" 133 "var socket = new WebSocket('%1/devtools/page/%2');\n" 134 "socket.onmessage = function(message) {\n" 135 "var response = JSON.parse(message.data);\n" 136 "if (response.id === 1)\n" 137 "document.title = response.result.result.value;\n" 138 "}\n" 139 "socket.onopen = function() {\n" 140 "socket.send('{\"id\": 1, \"method\": \"Runtime.evaluate\", \"params\": {\"expression\": \"%3\" } }');\n" 141 "}\n" 142 "</script>") 143 .arg(s_inspectorServerWebSocketBaseUrl.toString()) 144 .arg(pageList.at(0).toObject().value("id").toDouble()) 145 .arg(jsExpression)); 146 147 for (int i = 0; i < 10; ++i) { 148 if (!webSocketQueryWebView->title().isEmpty()) 149 break; 150 waitForSignal(webSocketQueryWebView.data(), SIGNAL(titleChanged()), 500); 151 } 152 153 QCOMPARE(webSocketQueryWebView->title(), jsExpressionResult); 154} 155 156void tst_InspectorServer::openRemoteDebuggingSession() 157{ 158 QJsonArray pageList = fetchPageList(); 159 QCOMPARE(pageList.size(), 1); 160 161 QScopedPointer<QQuickWebView> inspectorWebView(newWebView()); 162 LoadStartedCatcher catcher2(inspectorWebView.data()); 163 inspectorWebView->setUrl(s_inspectorServerHttpBaseUrl.resolved(QUrl(pageList.at(0).toObject().value("inspectorUrl").toString()))); 164 waitForSignal(&catcher2, SIGNAL(finished())); 165 for (int i = 0; i < 10; ++i) { 166 if (!inspectorWebView->title().isEmpty()) 167 break; 168 waitForSignal(inspectorWebView.data(), SIGNAL(titleChanged()), 500); 169 } 170 171 // To test the whole pipeline this exploits a behavior of the inspector front-end which won't provide any title unless the 172 // debugging session was established correctly through web socket. It should be something like "Web Inspector - <Page URL>". 173 // So this test case will fail if: 174 // - The page list didn't return a valid inspector URL 175 // - Or the front-end couldn't be loaded through the inspector HTTP server 176 // - Or the web socket connection couldn't be established between the front-end and the page through the inspector server 177 // Let's see if this test isn't raising too many false positives, in which case we should use a better predicate if available. 178 QVERIFY(!inspectorWebView->title().isEmpty()); 179} 180 181QTEST_MAIN(tst_InspectorServer) 182 183#include "tst_inspectorserver.moc" 184