1 /*
2     SPDX-FileCopyrightText: 2016 The Qt Company Ltd. <https://www.qt.io/licensing/>
3 
4     This file is part of the QtWebEngine module of the Qt Toolkit.
5     SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0 OR LicenseRef-Qt-Commercial
6 */
7 #ifndef WEBENGINE_TESTUTILS_H
8 #define WEBENGINE_TESTUTILS_H
9 
10 #include <QEventLoop>
11 #include <QTimer>
12 #include <QWebEnginePage>
13 
14 template<typename T, typename R>
15 struct RefWrapper {
16     R &ref;
operatorRefWrapper17     void operator()(const T& result) {
18         ref(result);
19     }
20 };
21 
22 template<typename T>
23 class CallbackSpy {
24 public:
CallbackSpy()25     CallbackSpy() : called(false) {
26         timeoutTimer.setSingleShot(true);
27         QObject::connect(&timeoutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
28     }
29 
waitForResult()30     T waitForResult() {
31         if (!called) {
32             timeoutTimer.start(10000);
33             eventLoop.exec();
34         }
35         return result;
36     }
37 
wasCalled()38     bool wasCalled() const {
39         return called;
40     }
41 
operator()42     void operator()(const T &result) {
43         this->result = result;
44         called = true;
45         eventLoop.quit();
46     }
47 
48     // Cheap rip-off of boost/std::ref
ref()49     RefWrapper<T, CallbackSpy<T> > ref()
50     {
51         RefWrapper<T, CallbackSpy<T> > wrapper = {*this};
52         return wrapper;
53     }
54 
55 private:
56     Q_DISABLE_COPY(CallbackSpy)
57     bool called;
58     QTimer timeoutTimer;
59     QEventLoop eventLoop;
60     T result;
61 };
62 
63 // taken from the qwebengine unittests
evaluateJavaScriptSync(QWebEnginePage * page,const QString & script)64 static inline QVariant evaluateJavaScriptSync(QWebEnginePage *page, const QString &script)
65 {
66     CallbackSpy<QVariant> spy;
67     page->runJavaScript(script, spy.ref());
68     return spy.waitForResult();
69 }
70 
71 // Taken from QtWebEngine's tst_qwebenginepage.cpp
elementCenter(QWebEnginePage * page,const QString & id)72 static QPoint elementCenter(QWebEnginePage *page, const QString &id)
73 {
74     QVariantList rectList = evaluateJavaScriptSync(page,
75             "(function(){"
76             "var elem = document.getElementById('" + id + "');"
77             "var rect = elem.getBoundingClientRect();"
78             "return [rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top];"
79             "})()").toList();
80 
81     if (rectList.count() != 4) {
82         qWarning("elementCenter failed.");
83         return QPoint();
84     }
85     const QRect rect(rectList.at(0).toInt(), rectList.at(1).toInt(),
86                      rectList.at(2).toInt(), rectList.at(3).toInt());
87     return rect.center();
88 }
89 #endif
90