summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets')
-rw-r--r--tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp171
-rw-r--r--tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp2
-rw-r--r--tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp94
-rw-r--r--tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp30
-rw-r--r--tests/auto/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp106
-rw-r--r--tests/auto/widgets/qwebenginepage/BLACKLIST2
-rw-r--r--tests/auto/widgets/qwebenginepage/qwebenginepage.pro2
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/basic_printing_page.html (renamed from tests/auto/widgets/qwebengineview/resources/basic_printing_page.html)0
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp419
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc1
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp91
-rw-r--r--tests/auto/widgets/qwebenginescript/resources/test_iframe_inner.html8
-rw-r--r--tests/auto/widgets/qwebenginescript/resources/test_iframe_main.html9
-rw-r--r--tests/auto/widgets/qwebenginescript/resources/test_iframe_outer.html9
-rw-r--r--tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp86
-rw-r--r--tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc7
-rw-r--r--tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp4
-rw-r--r--tests/auto/widgets/qwebengineshutdown/qwebengineshutdown.pro (renamed from tests/auto/widgets/qwebenginehistoryinterface/qwebenginehistoryinterface.pro)0
-rw-r--r--tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp95
-rw-r--r--tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic1
-rw-r--r--tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic1
-rw-r--r--tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp16
-rw-r--r--tests/auto/widgets/qwebengineview/BLACKLIST8
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp468
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc1
-rw-r--r--tests/auto/widgets/tests.pri2
-rw-r--r--tests/auto/widgets/util.h14
-rw-r--r--tests/auto/widgets/widgets.pro8
28 files changed, 1279 insertions, 376 deletions
diff --git a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
index 3d2c04486..759158a50 100644
--- a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
+++ b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
@@ -40,6 +40,8 @@ private Q_SLOTS:
void hierarchy();
void text();
void value();
+ void roles_data();
+ void roles();
};
// This will be called before the first test function is executed.
@@ -248,6 +250,175 @@ void tst_QWebEngineAccessibility::value()
QCOMPARE(progressBarValueInterface->maximumValue().toInt(), 99);
}
+void tst_QWebEngineAccessibility::roles_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::addColumn<bool>("isSection");
+ QTest::addColumn<QAccessible::Role>("role");
+
+ QTest::newRow("AX_ROLE_ABBR") << QString("<abbr>a</abbr>") << false << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_ALERT") << QString("<div role='alert'>alert</div>") << true << QAccessible::AlertMessage;
+ QTest::newRow("AX_ROLE_ALERT_DIALOG") << QString("<div role='alertdialog'>alert</div>") << true << QAccessible::AlertMessage;
+ //QTest::newRow("AX_ROLE_ANCHOR") << QString("<a>target</a>") << false << QAccessible::Link; // FIXME: The test case might be wrong (see https://codereview.chromium.org/2713193003)
+ QTest::newRow("AX_ROLE_ANNOTATION") << QString("<rt>a</rt>") << false << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_APPLICATION") << QString("<div role='application'>landmark</div>") << true << QAccessible::Document;
+ QTest::newRow("AX_ROLE_ARTICLE") << QString("<article>a</article>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_AUDIO") << QString("<audio controls><source src='test.mp3' type='audio/mpeg'></audio>") << false << QAccessible::Sound;
+ QTest::newRow("AX_ROLE_BANNER") << QString("<header>a</header>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_BLOCKQUOTE") << QString("<blockquote>a</blockquote>") << true << QAccessible::Section;
+ //QTest::newRow("AX_ROLE_BUSY_INDICATOR"); // Deprecated
+ QTest::newRow("AX_ROLE_BUTTON") << QString("<button>a</button>") << false << QAccessible::Button;
+ //QTest::newRow("AX_ROLE_BUTTON_DROP_DOWN"); // Not a blink accessibility role
+ //QTest::newRow("AX_ROLE_CANVAS") << QString("<canvas width='10' height='10'></canvas>") << true << QAccessible::Canvas; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
+ QTest::newRow("AX_ROLE_CAPTION") << QString("<table><caption>a</caption></table>") << false << QAccessible::Heading;
+ //QTest::newRow("AX_ROLE_CARET"); // Not a blink accessibility role
+ //QTest::newRow("AX_ROLE_CELL") << QString("<td role='cell'>a</td>") << true << QAccessible::Cell; // FIXME: Aria role 'cell' should work for <td>
+ QTest::newRow("AX_ROLE_CHECK_BOX") << QString("<input type='checkbox'>a</input>") << false << QAccessible::CheckBox;
+ QTest::newRow("AX_ROLE_CLIENT") << QString("") << true << QAccessible::Client;
+ QTest::newRow("AX_ROLE_COLOR_WELL") << QString("<input type='color'>a</input>") << false << QAccessible::ColorChooser;
+ //QTest::newRow("AX_ROLE_COLUMN") << QString("<table><tr><td>a</td></tr>") << true << QAccessible::Column; // FIXME: The test case might be wrong (see AXTableColumn.h)
+ QTest::newRow("AX_ROLE_COLUMN_HEADER") << QString("<div role='columnheader'>a</div>") << true << QAccessible::ColumnHeader;
+ QTest::newRow("AX_ROLE_COMBO_BOX") << QString("<select><option>a</option></select>") << false << QAccessible::ComboBox;
+ QTest::newRow("AX_ROLE_COMPLEMENTARY") << QString("<aside>a</aside>") << true << QAccessible::ComplementaryContent;
+ QTest::newRow("AX_ROLE_CONTENT_INFO") << QString("<address>a</address>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_DATE") << QString("<input type='date'></input>") << false << QAccessible::Clock;
+ QTest::newRow("AX_ROLE_DATE_TIME") << QString("<input type='datetime-local'></input>") << false << QAccessible::Clock;
+ QTest::newRow("AX_ROLE_DEFINITION") << QString("<div role='definition'>landmark</div>") << true << QAccessible::Paragraph;
+ QTest::newRow("AX_ROLE_DESCRIPTION_LIST") << QString("<dl>a</dl>") << true << QAccessible::List;
+ QTest::newRow("AX_ROLE_DESCRIPTION_LIST_DETAIL") << QString("<dd>a</dd>") << true << QAccessible::Paragraph;
+ QTest::newRow("AX_ROLE_DESCRIPTION_LIST_TERM") << QString("<dt>a</dt>") << true << QAccessible::ListItem;
+ QTest::newRow("AX_ROLE_DETAILS") << QString("<details>a</details>") << true << QAccessible::Grouping;
+ //QTest::newRow("AX_ROLE_DESKTOP"); // Not a blink accessibility role
+ QTest::newRow("AX_ROLE_DIALOG") << QString("<div role='dialog'></div>") << true << QAccessible::Dialog;
+ //QTest::newRow("AX_ROLE_DIRECTORY") << QString("<div role='directory'></div>") << true << QAccessible::NoRole; // FIXME: Aria role 'directory' should work
+ QTest::newRow("AX_ROLE_DISCLOSURE_TRIANGLE") << QString("<details><summary>a</summary></details>") << false << QAccessible::NoRole;
+ QTest::newRow("AX_ROLE_GENERIC_CONTAINER") << QString("<div>a</div>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_DOCUMENT") << QString("<div role='document'>a</div>") << true << QAccessible::Document;
+ QTest::newRow("AX_ROLE_EMBEDDED_OBJECT") << QString("<object width='10' height='10'></object>") << false << QAccessible::Grouping;
+ QTest::newRow("AX_ROLE_FEED") << QString("<div role='feed'>a</div>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_FIGCAPTION") << QString("<figcaption>a</figcaption>") << true << QAccessible::Heading;
+ QTest::newRow("AX_ROLE_FIGURE") << QString("<figure>a</figure>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_FOOTER") << QString("<footer>a</footer>") << true << QAccessible::Footer;
+ QTest::newRow("AX_ROLE_FORM") << QString("<form></form>") << true << QAccessible::Form;
+ QTest::newRow("AX_ROLE_GRID") << QString("<div role='grid'></div>") << true << QAccessible::Table;
+ QTest::newRow("AX_ROLE_GROUP") << QString("<fieldset></fieldset>") << true << QAccessible::Grouping;
+ QTest::newRow("AX_ROLE_HEADING") << QString("<h1>a</h1>") << true << QAccessible::Heading;
+ QTest::newRow("AX_ROLE_IFRAME") << QString("<iframe>a</iframe>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_IFRAME_PRESENTATIONAL") << QString("<iframe role='presentation'>a</iframe>") << false << QAccessible::NoRole;
+ //QTest::newRow("AX_ROLE_IGNORED") << QString("<tag>a</tag>") << true << QAccessible::NoRole; // FIXME: The HTML element should not be exposed as an element (see AXNodeObject.cpp)
+ QTest::newRow("AX_ROLE_IMAGE") << QString("<img>") << false << QAccessible::Graphic;
+ //QTest::newRow("AX_ROLE_IMAGE_MAP") << QString("<map>a</map>") << true << QAccessible::Graphic; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
+ //QTest::newRow("AX_ROLE_IMAGE_MAP_LINK") << QString("<map>a</map>") << true << QAccessible::Graphic; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
+ QTest::newRow("AX_ROLE_INLINE_TEXT_BOX") << QString("<textarea rows='4' cols='50'></textarea>") << false << QAccessible::EditableText;
+ QTest::newRow("AX_ROLE_INPUT_TIME") << QString("<input type='time'></input>") << false << QAccessible::SpinBox;
+ QTest::newRow("AX_ROLE_LABEL_TEXT") << QString("<label>a</label>") << false << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_LEGEND") << QString("<legend>a</legend>") << true << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_LINE_BREAK") << QString("<br>") << false << QAccessible::Separator;
+ QTest::newRow("AX_ROLE_LINK") << QString("<a href=''>link</a>") << false << QAccessible::Link;
+ QTest::newRow("AX_ROLE_LIST") << QString("<ul></ul>") << true << QAccessible::List;
+ QTest::newRow("AX_ROLE_LIST_BOX") << QString("<select role='listbox'></select>") << false << QAccessible::ComboBox;
+ QTest::newRow("AX_ROLE_LIST_BOX_OPTION") << QString("<option>a</option>") << true << QAccessible::ListItem;
+ QTest::newRow("AX_ROLE_LIST_ITEM") << QString("<li>a</li>") << true << QAccessible::ListItem;
+ QTest::newRow("AX_ROLE_LIST_MARKER") << QString("<li><ul></ul></li>") << false << QAccessible::StaticText;
+ //QTest::newRow("AX_ROLE_LOCATION_BAR"); // Not a blink accessibility role
+ QTest::newRow("AX_ROLE_LOG") << QString("<div role='log'>a</div>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_MAIN") << QString("<main>a</main>") << true << QAccessible::Grouping;
+ QTest::newRow("AX_ROLE_MARK") << QString("<mark>a</mark>") << false << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_MARQUEE") << QString("<div role='marquee'>a</div>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_MATH") << QString("<math>a</math>") << false << QAccessible::Equation;
+ QTest::newRow("AX_ROLE_MENU") << QString("<div role='menu'>a</div>") << true << QAccessible::PopupMenu;
+ QTest::newRow("AX_ROLE_MENU_BAR") << QString("<div role='menubar'>a</div>") << true << QAccessible::MenuBar;
+ QTest::newRow("AX_ROLE_MENU_ITEM") << QString("<menu role='menu'><input type='button' /></menu>") << false << QAccessible::MenuItem;
+ QTest::newRow("AX_ROLE_MENU_ITEM_CHECK_BOX") << QString("<menu role='menu'><input type='checkbox'></input></menu>") << false << QAccessible::CheckBox;
+ QTest::newRow("AX_ROLE_MENU_ITEM_RADIO") << QString("<menu role='menu'><input type='radio'></input></menu>") << false << QAccessible::RadioButton;
+ QTest::newRow("AX_ROLE_MENU_BUTTON") << QString("<menu role='group'><div role='menuitem'>a</div></menu>") << false << QAccessible::MenuItem;
+ //QTest::newRow("AX_ROLE_MENU_LIST_OPTION") << QString("<select role='menu'><option>a</option></select>") << false << QAccessible::MenuItem; // FIXME: <select> should be a menu list (see AXMenuListOption.cpp)
+ //QTest::newRow("AX_ROLE_MENU_LIST_POPUP") << QString("<menu type='context'>a</menu>") << true << QAccessible::PopupMenu; // FIXME: <menu> is not fully supported by Chromium (see AXMenuListPopup.h)
+ QTest::newRow("AX_ROLE_METER") << QString("<meter>a</meter>") << false << QAccessible::Chart;
+ QTest::newRow("AX_ROLE_NAVIGATION") << QString("<nav>a</nav>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_NOTE") << QString("<div role='note'>a</div>") << true << QAccessible::Note;
+ //QTest::newRow("AX_ROLE_OUTLINE"); // No mapping to ARIA role
+ //QTest::newRow("AX_ROLE_PANE"); // Not a blink accessibility role
+ QTest::newRow("AX_ROLE_PARAGRAH") << QString("<p>a</p>") << true << QAccessible::Paragraph;
+ QTest::newRow("AX_ROLE_POP_UP_BUTTON") << QString("<select multiple></select>") << false << QAccessible::ComboBox;
+ QTest::newRow("AX_ROLE_PRE") << QString("<pre>a</pre>") << true << QAccessible::Section;
+ //QTest::newRow("AX_ROLE_PRESENTATIONAL") << QString("<div role='presentation'>a</div>") << true << QAccessible::NoRole; // FIXME: Aria role 'presentation' should work
+ QTest::newRow("AX_ROLE_PROGRESS_INDICATOR") << QString("<div role='progressbar' aria-valuenow='77' aria-valuemin='22' aria-valuemax='99'></div>") << true << QAccessible::ProgressBar;
+ QTest::newRow("AX_ROLE_RADIO_BUTTON") << QString("<input type='radio'></input>") << false << QAccessible::RadioButton;
+ QTest::newRow("AX_ROLE_RADIO_GROUP") << QString("<fieldset role='radiogroup'></fieldset>") << true << QAccessible::Grouping;
+ QTest::newRow("AX_ROLE_REGION") << QString("<section>a</section>") << true << QAccessible::Section;
+ //QTest::newRow("AX_ROLE_ROW") << QString("<tr role='row'>a</tr>") << true << QAccessible::Row; // FIXME: Aria role 'row' should work for <tr>
+ //QTest::newRow("AX_ROLE_ROW_HEADER") << QString("<td role='rowheader'>a</td>") << true << QAccessible::RowHeader; // FIXME: Aria role 'rowheader' should work for <td>
+ QTest::newRow("AX_ROLE_RUBY") << QString("<ruby>a</ruby>") << false << QAccessible::StaticText;
+ //QTest::newRow("AX_ROLE_RULER"); // No mapping to ARIA role
+ //QTest::newRow("AX_ROLE_SCROLL_AREA"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_SCROLL_BAR") << QString("<div role='scrollbar'>a</a>") << true << QAccessible::ScrollBar;
+ //QTest::newRow("AX_ROLE_SEAMLESS_WEB_AREA"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_SEARCH") << QString("<div role='search'>landmark</div>") << true << QAccessible::Section;
+ QTest::newRow("AX_ROLE_SEARCH_BOX") << QString("<input type='search'></input>") << false << QAccessible::EditableText;
+ QTest::newRow("AX_ROLE_SLIDER") << QString("<input type='range'></input>") << false << QAccessible::Slider;
+ //QTest::newRow("AX_ROLE_SLIDER_THUMB"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_SPIN_BUTTON") << QString("<input type='number'></input>") << false << QAccessible::SpinBox;
+ //QTest::newRow("AX_ROLE_SPIN_BUTTON_PART"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_SPLITER") << QString("<hr>") << true << QAccessible::Splitter;
+ QTest::newRow("AX_ROLE_STATIC_TEXT") << QString("a") << false << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_STATUS") << QString("<output>a</output>") << false << QAccessible::Indicator;
+ QTest::newRow("AX_ROLE_SVG_ROOT") << QString("<svg width='10' height='10'></svg>") << false << QAccessible::Graphic;
+ QTest::newRow("AX_ROLE_SWITCH") << QString("<button aria-checked='false'>a</button>") << false << QAccessible::Button;
+ //QTest::newRow("AX_ROLE_TABLE") << QString("<table>a</table>") << true << QAccessible::Table; // FIXME: The test case might be wrong (see AXTable.cpp)
+ //QTest::newRow("AX_ROLE_TABLE_HEADER_CONTAINER"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_TAB") << QString("<div role='tab'>a</div>") << true << QAccessible::PageTab;
+ //QTest::newRow("AX_ROLE_TAB_GROUP"); // No mapping to ARIA role
+ QTest::newRow("AX_ROLE_TAB_LIST") << QString("<div role='tablist'>a</div>") << true << QAccessible::PageTabList;
+ QTest::newRow("AX_ROLE_TAB_PANEL") << QString("<div role='tab'>a</div>") << true << QAccessible::PageTab;
+ QTest::newRow("AX_ROLE_TERM") << QString("<div role='term'>a</div>") << true << QAccessible::StaticText;
+ QTest::newRow("AX_ROLE_TEXT_FIELD") << QString("<input type='text'></input>") << false << QAccessible::EditableText;
+ QTest::newRow("AX_ROLE_TIME") << QString("<time>a</time>") << false << QAccessible::Clock;
+ QTest::newRow("AX_ROLE_TIMER") << QString("<div role='timer'>a</div>") << true << QAccessible::Clock;
+ //QTest::newRow("AX_ROLE_TITLE_BAR"); // Not a blink accessibility role
+ QTest::newRow("AX_ROLE_TOGGLE_BUTTON") << QString("<button aria-pressed='false'>a</button>") << false << QAccessible::Button;
+ QTest::newRow("AX_ROLE_TOOLBAR") << QString("<div role='toolbar'>a</div>") << true << QAccessible::ToolBar;
+ QTest::newRow("AX_ROLE_TOOLTIP") << QString("<div role='tooltip'>a</div>") << true << QAccessible::ToolTip;
+ QTest::newRow("AX_ROLE_TREE") << QString("<div role='tree'>a</div>") << true << QAccessible::Tree;
+ QTest::newRow("AX_ROLE_TREE_GRID") << QString("<div role='treegrid'>a</div>") << true << QAccessible::Tree;
+ QTest::newRow("AX_ROLE_TREE_ITEM") << QString("<div role='treeitem'>a</div>") << true << QAccessible::TreeItem;
+ QTest::newRow("AX_ROLE_VIDEO") << QString("<video><source src='test.mp4' type='video/mp4'></video>") << false << QAccessible::Animation;
+ //QTest::newRow("AX_ROLE_WINDOW"); // No mapping to ARIA role
+}
+
+void tst_QWebEngineAccessibility::roles()
+{
+ QFETCH(QString, html);
+ QFETCH(bool, isSection);
+ QFETCH(QAccessible::Role, role);
+
+ QWebEngineView webView;
+ webView.setHtml("<html><body>" + html + "</body></html>");
+ QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
+ QVERIFY(spyFinished.wait());
+
+ QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
+
+ // Corner case for Client role
+ if (html.isEmpty()) {
+ QCOMPARE(view->role(), QAccessible::Client);
+ return;
+ }
+
+ QTRY_COMPARE(view->child(0)->childCount(), 1);
+ QAccessibleInterface *document = view->child(0);
+ QAccessibleInterface *section = document->child(0);
+
+ if (isSection) {
+ QCOMPARE(section->role(), role);
+ return;
+ }
+
+ QVERIFY(section->childCount() > 0);
+ QAccessibleInterface *element = section->child(0);
+ QCOMPARE(element->role(), role);
+}
+
static QByteArrayList params = QByteArrayList()
<< "--force-renderer-accessibility";
diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp
index 79fc57ac0..3ac8943a5 100644
--- a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp
+++ b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp
@@ -43,7 +43,7 @@ private Q_SLOTS:
void tst_QWebEngineDefaultSurfaceFormat::customDefaultSurfaceFormat()
{
-#if !defined(Q_OS_MACOSX)
+#if !defined(Q_OS_MACOS)
QSKIP("OpenGL Core Profile is currently only supported on macOS.");
#endif
// Setting a new default QSurfaceFormat with a core OpenGL profile before
diff --git a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp b/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
index c25e82d41..83e8d1101 100644
--- a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
+++ b/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp
@@ -38,6 +38,18 @@
#include <httpserver.h>
#include <waitforsignal.h>
+static std::unique_ptr<HttpReqRep> waitForFaviconRequest(HttpServer *server)
+{
+ auto rr = waitForRequest(server);
+ if (!rr ||
+ rr->requestMethod() != QByteArrayLiteral("GET") ||
+ rr->requestPath() != QByteArrayLiteral("/favicon.ico"))
+ return nullptr;
+ rr->setResponseStatus(404);
+ rr->sendResponse();
+ return std::move(rr);
+}
+
class tst_QWebEngineDownloads : public QObject
{
Q_OBJECT
@@ -47,6 +59,7 @@ private Q_SLOTS:
void downloadTwoLinks();
void downloadPage_data();
void downloadPage();
+ void downloadViaSetUrl();
};
enum DownloadTestUserAction {
@@ -318,17 +331,14 @@ void tst_QWebEngineDownloads::downloadLink()
QVERIFY(loadOk);
// 1.1. Ignore favicon request
- auto favIconRR = waitForRequest(&server);
+ auto favIconRR = waitForFaviconRequest(&server);
QVERIFY(favIconRR);
- QCOMPARE(favIconRR->requestMethod(), QByteArrayLiteral("GET"));
- QCOMPARE(favIconRR->requestPath(), QByteArrayLiteral("/favicon.ico"));
- favIconRR->setResponseStatus(404);
- favIconRR->sendResponse();
// 2. Simulate user action
//
// - Navigate: user left-clicks on link
// - SaveLink: user right-clicks on link and chooses "save link as" from menu
+ QTRY_VERIFY(view.focusWidget());
QWidget *renderWidget = view.focusWidget();
QPoint linkPos(10, 10);
if (userAction == SaveLink) {
@@ -450,11 +460,10 @@ void tst_QWebEngineDownloads::downloadTwoLinks()
QTRY_COMPARE(requestSpy.count(), 2);
std::unique_ptr<HttpReqRep> favIconRR(results.takeFirst());
QVERIFY(favIconRR);
- QCOMPARE(favIconRR->requestMethod(), QByteArrayLiteral("GET"));
- QCOMPARE(favIconRR->requestPath(), QByteArrayLiteral("/favicon.ico"));
favIconRR->setResponseStatus(404);
favIconRR->sendResponse();
+ QTRY_VERIFY(view.focusWidget());
QWidget *renderWidget = view.focusWidget();
QTest::mouseClick(renderWidget, Qt::LeftButton, {}, QPoint(10, 10));
QTest::mouseClick(renderWidget, Qt::LeftButton, {}, QPoint(10, 30));
@@ -551,12 +560,8 @@ void tst_QWebEngineDownloads::downloadPage()
QVERIFY(waitForSignal(&page, &QWebEnginePage::loadFinished, [&](bool ok){ loadOk = ok; }));
QVERIFY(loadOk);
- auto favIconRR = waitForRequest(&server);
+ auto favIconRR = waitForFaviconRequest(&server);
QVERIFY(favIconRR);
- QCOMPARE(favIconRR->requestMethod(), QByteArrayLiteral("GET"));
- QCOMPARE(favIconRR->requestPath(), QByteArrayLiteral("/favicon.ico"));
- favIconRR->setResponseStatus(404);
- favIconRR->sendResponse();
QTemporaryDir tmpDir;
QVERIFY(tmpDir.isValid());
@@ -603,5 +608,70 @@ void tst_QWebEngineDownloads::downloadPage()
QVERIFY(file.exists());
}
+void tst_QWebEngineDownloads::downloadViaSetUrl()
+{
+ // Reproduce the scenario described in QTBUG-63388 by triggering downloads
+ // of the same file multiple times via QWebEnginePage::setUrl
+
+ HttpServer server;
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy urlSpy(&page, &QWebEnginePage::urlChanged);
+ const QUrl indexUrl = server.url();
+ const QUrl fileUrl = server.url(QByteArrayLiteral("/file"));
+
+ // Set up the test scenario by trying to load some unrelated HTML.
+
+ page.setUrl(indexUrl);
+
+ auto indexRR = waitForRequest(&server);
+ QVERIFY(indexRR);
+ QCOMPARE(indexRR->requestMethod(), QByteArrayLiteral("GET"));
+ QCOMPARE(indexRR->requestPath(), QByteArrayLiteral("/"));
+ indexRR->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("text/html"));
+ indexRR->setResponseBody(QByteArrayLiteral("<html><body>Hello</body></html>"));
+ indexRR->sendResponse();
+
+ auto indexFavRR = waitForFaviconRequest(&server);
+ QVERIFY(indexFavRR);
+
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(urlSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), indexUrl);
+
+ // Download files via setUrl. With QTBUG-63388 after the first iteration the
+ // downloads would be triggered for indexUrl and not fileUrl.
+
+ QVector<QUrl> downloadUrls;
+ QObject::connect(&profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ downloadUrls.append(item->url());
+ });
+
+ for (int i = 0; i != 3; ++i) {
+ page.setUrl(fileUrl);
+ QCOMPARE(page.url(), fileUrl);
+
+ auto fileRR = waitForRequest(&server);
+ QVERIFY(fileRR);
+ fileRR->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
+ fileRR->setResponseBody(QByteArrayLiteral("redacted"));
+ fileRR->sendResponse();
+
+ auto fileFavRR = waitForFaviconRequest(&server);
+ QVERIFY(fileFavRR);
+
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(urlSpy.count(), 2);
+ QTRY_COMPARE(downloadUrls.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), fileUrl);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), indexUrl);
+ QCOMPARE(downloadUrls.takeFirst(), fileUrl);
+ QCOMPARE(page.url(), indexUrl);
+ }
+}
+
QTEST_MAIN(tst_QWebEngineDownloads)
#include "tst_qwebenginedownloads.moc"
diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
index d9bbce173..9fceffd7e 100644
--- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
+++ b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp
@@ -40,6 +40,7 @@ protected :
loadFinishedSpy->clear();
page->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html"));
QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ loadFinishedSpy->clear();
}
public Q_SLOTS:
@@ -160,7 +161,7 @@ void tst_QWebEngineHistory::forward()
while (hist->canGoBack()) {
hist->back();
histBackCount++;
- QTRY_COMPARE(loadFinishedSpy->count(), histBackCount+1);
+ QTRY_COMPARE(loadFinishedSpy->count(), histBackCount);
}
QSignalSpy titleChangedSpy(page, SIGNAL(titleChanged(const QString&)));
@@ -197,15 +198,15 @@ void tst_QWebEngineHistory::goToItem()
QWebEngineHistoryItem current = hist->currentItem();
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->count(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 3);
+ QTRY_COMPARE(loadFinishedSpy->count(), 2);
QVERIFY(hist->currentItem().title() != current.title());
hist->goToItem(current);
- QTRY_COMPARE(loadFinishedSpy->count(), 3);
+ QTRY_COMPARE(loadFinishedSpy->count(), 2);
QTRY_COMPARE(hist->currentItem().title(), current.title());
}
@@ -228,10 +229,10 @@ void tst_QWebEngineHistory::items()
void tst_QWebEngineHistory::backForwardItems()
{
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_COMPARE(loadFinishedSpy->count(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 3);
+ QTRY_COMPARE(loadFinishedSpy->count(), 2);
QTRY_COMPARE(hist->items().size(), 5);
QTRY_COMPARE(hist->backItems(100).size(), 2);
@@ -281,16 +282,17 @@ void tst_QWebEngineHistory::serialize_2()
// Force a "same document" navigation.
page->load(page->url().toString() + QLatin1String("#dummyAnchor"));
- QTRY_COMPARE(loadFinishedSpy->count(), 1);
+ // "same document" navigation doesn't trigger loadFinished signal.
+ QTRY_COMPARE(evaluateJavaScriptSync(page, "location.hash").toString(), QStringLiteral("#dummyAnchor"));
int initialCurrentIndex = hist->currentItemIndex();
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 2);
+ QTRY_VERIFY(evaluateJavaScriptSync(page, "location.hash").toString().isEmpty());
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 3);
+ QTRY_COMPARE(loadFinishedSpy->count(), 1);
hist->back();
- QTRY_COMPARE(loadFinishedSpy->count(), 4);
+ QTRY_COMPARE(loadFinishedSpy->count(), 2);
//check if current index was changed (make sure that it is not last item)
QVERIFY(hist->currentItemIndex() != initialCurrentIndex);
//save current index
@@ -301,17 +303,17 @@ void tst_QWebEngineHistory::serialize_2()
load >> *hist;
QVERIFY(load.status() == QDataStream::Ok);
// Restoring the history will trigger a load.
- QTRY_COMPARE(loadFinishedSpy->count(), 5);
+ QTRY_COMPARE(loadFinishedSpy->count(), 3);
//check current index
QTRY_COMPARE(hist->currentItemIndex(), oldCurrentIndex);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 6);
+ QTRY_COMPARE(loadFinishedSpy->count(), 4);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 7);
+ QTRY_COMPARE(loadFinishedSpy->count(), 5);
hist->forward();
- QTRY_COMPARE(loadFinishedSpy->count(), 8);
+ QTRY_COMPARE(loadFinishedSpy->count(), 6);
QTRY_COMPARE(hist->currentItemIndex(), initialCurrentIndex);
}
diff --git a/tests/auto/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp b/tests/auto/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp
deleted file mode 100644
index 4666d1ba4..000000000
--- a/tests/auto/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- Copyright (C) 2008 Holger Hans Peter Freyther
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-
-#include <QtTest/QtTest>
-
-#include <qwebenginepage.h>
-#include <qwebengineview.h>
-#if defined(QWEBENGINEHISTORYINTERFACE)
-#include <qwebenginehistoryinterface.h>
-#endif
-#include <QDebug>
-
-class tst_QWebEngineHistoryInterface : public QObject
-{
- Q_OBJECT
-
-public:
- tst_QWebEngineHistoryInterface();
- virtual ~tst_QWebEngineHistoryInterface();
-
-public Q_SLOTS:
- void initTestCase();
- void init();
- void cleanup();
-
-private Q_SLOTS:
- void visitedLinks();
-
-private:
-
-
-private:
- QWebEngineView* m_view;
- QWebEnginePage* m_page;
-};
-
-tst_QWebEngineHistoryInterface::tst_QWebEngineHistoryInterface()
-{
-}
-
-tst_QWebEngineHistoryInterface::~tst_QWebEngineHistoryInterface()
-{
-}
-
-void tst_QWebEngineHistoryInterface::initTestCase()
-{
-}
-
-void tst_QWebEngineHistoryInterface::init()
-{
- m_view = new QWebEngineView();
- m_page = m_view->page();
-}
-
-void tst_QWebEngineHistoryInterface::cleanup()
-{
- delete m_view;
-}
-
-#if defined(QWEBENGINEHISTORYINTERFACE)
-class FakeHistoryImplementation : public QWebEngineHistoryInterface {
-public:
- void addHistoryEntry(const QString&) {}
- bool historyContains(const QString& url) const {
- return url == QLatin1String("http://www.trolltech.com/");
- }
-};
-#endif
-
-/*
- * Test that visited links are properly colored. http://www.trolltech.com is marked
- * as visited, so the below website should have exactly one element in the a:visited
- * state.
- */
-void tst_QWebEngineHistoryInterface::visitedLinks()
-{
-#if !defined(QWEBENGINEELEMENT)
- QSKIP("QWEBENGINEELEMENT");
-#else
- QWebEngineHistoryInterface::setDefaultInterface(new FakeHistoryImplementation);
- m_view->setHtml("<html><style>:link{color:green}:visited{color:red}</style><body><a href='http://www.trolltech.com' id='vlink'>Trolltech</a></body></html>");
- QWebEngineElement anchor = m_view->page()->mainFrame()->findFirstElement("a[id=vlink]");
- QString linkColor = anchor.styleProperty("color", QWebEngineElement::ComputedStyle);
- QCOMPARE(linkColor, QString::fromLatin1("rgb(255, 0, 0)"));
-#endif
-}
-
-QTEST_MAIN(tst_QWebEngineHistoryInterface)
-#include "tst_qwebenginehistoryinterface.moc"
diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST
index b376cd375..7470a1523 100644
--- a/tests/auto/widgets/qwebenginepage/BLACKLIST
+++ b/tests/auto/widgets/qwebenginepage/BLACKLIST
@@ -7,8 +7,6 @@
[macCopyUnicodeToClipboard]
osx
-[getUserMediaRequest]
-*
[mouseMovementProperties]
osx-10.11
osx-10.12
diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
index e0765736e..47c09e1ce 100644
--- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
+++ b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
@@ -1,4 +1,4 @@
include(../tests.pri)
QT *= core-private
-contains(WEBENGINE_CONFIG, use_pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED
+qtConfig(webengine-printing-and-pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED
diff --git a/tests/auto/widgets/qwebengineview/resources/basic_printing_page.html b/tests/auto/widgets/qwebenginepage/resources/basic_printing_page.html
index 0c6ff379f..0c6ff379f 100644
--- a/tests/auto/widgets/qwebengineview/resources/basic_printing_page.html
+++ b/tests/auto/widgets/qwebenginepage/resources/basic_printing_page.html
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 182094a11..54cf27066 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -106,6 +106,7 @@ private Q_SLOTS:
void updatePositionDependentActionsCrash();
void createPluginWithPluginsEnabled();
void createPluginWithPluginsDisabled();
+ void callbackSpyDeleted();
void destroyPlugin_data();
void destroyPlugin();
void createViewlessPlugin_data();
@@ -126,7 +127,10 @@ private Q_SLOTS:
void userAgentNewlineStripping();
void undoActionHaveCustomText();
void renderWidgetHostViewNotShowTopLevel();
+ void getUserMediaRequest_data();
void getUserMediaRequest();
+ void getUserMediaRequestDesktopAudio();
+ void getUserMediaRequestSettingDisabled();
void savePage();
void crashTests_LazyInitializationOfMainFrame();
@@ -182,7 +186,6 @@ private Q_SLOTS:
void baseUrl_data();
void baseUrl();
void scrollPosition();
- void scrollToAnchor();
void scrollbarsOff();
void evaluateWillCauseRepaint();
void setContent_data();
@@ -191,6 +194,8 @@ private Q_SLOTS:
void setUrlWithPendingLoads();
void setUrlToEmpty();
void setUrlToInvalid();
+ void setUrlToBadDomain();
+ void setUrlToBadPort();
void setUrlHistory();
void setUrlUsingStateObject();
void setUrlThenLoads_data();
@@ -251,6 +256,7 @@ void tst_QWebEnginePage::init()
m_view = new QWebEngineView();
m_page = m_view->page();
m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ m_view->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
}
void tst_QWebEnginePage::cleanup()
@@ -308,6 +314,10 @@ void tst_QWebEnginePage::acceptNavigationRequest()
NavigationRequestOverride* newPage = new NavigationRequestOverride(&view, false);
view.setPage(newPage);
+ // acceptNavigationRequest and QWebEngineUrlRequestInterceptor::interceptRequest are not called
+ // for data: urls, which means the test is broken, aka setting
+ // newPage->m_acceptNavigationRequest to false does nothing to stop the page from loading.
+ // See QTBUG-50922 comments.
view.setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
"<input type='text'><input type='submit'></form></body></html>"), QUrl());
QTRY_COMPARE(loadSpy.count(), 1);
@@ -442,6 +452,22 @@ static QImage imageWithoutAlpha(const QImage &image)
return result;
}
+void tst_QWebEnginePage::callbackSpyDeleted()
+{
+ QWebEnginePage *page = m_view->page();
+ CallbackSpy<QVariant> spy;
+ QString poorManSleep("function wait(ms){"
+ " var start = new Date().getTime();"
+ " var end = start;"
+ " while (start + ms > end) {"
+ "end = new Date().getTime();"
+ " }"
+ "}"
+ "wait(1000);");
+ page->runJavaScript(poorManSleep, spy.ref());
+ //spy deleted before callback
+}
+
void tst_QWebEnginePage::pasteImage()
{
// Pixels with an alpha value of 0 will have different RGB values after the
@@ -459,7 +485,9 @@ void tst_QWebEnginePage::pasteImage()
"window.myImageDataURL ? window.myImageDataURL.length : 0").toInt() > 0);
QByteArray data = evaluateJavaScriptSync(page, "window.myImageDataURL").toByteArray();
data.remove(0, data.indexOf(";base64,") + 8);
- const QImage image = QImage::fromData(QByteArray::fromBase64(data), "PNG");
+ QImage image = QImage::fromData(QByteArray::fromBase64(data), "PNG");
+ if (image.format() == QImage::Format_RGB32)
+ image.reinterpretAsFormat(QImage::Format_ARGB32);
QCOMPARE(image, origImage);
}
@@ -2114,29 +2142,55 @@ void tst_QWebEnginePage::testStopScheduledPageRefresh()
void tst_QWebEnginePage::findText()
{
- QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
- m_page->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>"));
+ QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
+ m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>"));
+
+ // Showing is required, otherwise all find operations fail.
+ m_view->show();
QTRY_COMPARE(loadSpy.count(), 1);
// Select whole page contents.
- m_page->triggerAction(QWebEnginePage::SelectAll);
- QTRY_COMPARE(m_page->hasSelection(), true);
+ m_view->page()->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(m_view->hasSelection(), true);
- // Invoke a stopFinding() operation, which should clear the currently selected text.
- m_page->findText("");
- QTRY_VERIFY(m_page->selectedText().isEmpty());
+ // Invoking a stopFinding operation will not change or clear the currently selected text,
+ // if nothing was found beforehand.
+ {
+ CallbackSpy<bool> spy;
+ m_view->findText("", 0, spy.ref());
+ QVERIFY(spy.wasCalled());
+ QTRY_COMPARE(m_view->selectedText(), QString("foo bar"));
+ }
- QStringList words = (QStringList() << "foo" << "bar");
- foreach (QString subString, words) {
- // Invoke a find operation, which should clear the currently selected text, should
- // highlight all the found ocurrences, but should not update the selected text to the
- // searched for string.
- m_page->findText(subString);
- QTRY_VERIFY(m_page->selectedText().isEmpty());
-
- // Search highlights should be cleared, selected text should still be empty.
- m_page->findText("");
- QTRY_VERIFY(m_page->selectedText().isEmpty());
+ // Invoking a startFinding operation with text that won't be found, will clear the current
+ // selection.
+ {
+ CallbackSpy<bool> spy;
+ m_view->findText("Will not be found", 0, spy.ref());
+ QCOMPARE(spy.waitForResult(), false);
+ QTRY_VERIFY(m_view->selectedText().isEmpty());
+ }
+
+ // Select whole page contents again.
+ m_view->page()->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(m_view->hasSelection(), true);
+
+ // Invoking a startFinding operation with text that will be found, will clear the current
+ // selection as well.
+ {
+ CallbackSpy<bool> spy;
+ m_view->findText("foo", 0, spy.ref());
+ QVERIFY(spy.waitForResult());
+ QTRY_VERIFY(m_view->selectedText().isEmpty());
+ }
+
+ // Invoking a stopFinding operation after text was found, will set the selected text to the
+ // found text.
+ {
+ CallbackSpy<bool> spy;
+ m_view->findText("", 0, spy.ref());
+ QTRY_VERIFY(spy.wasCalled());
+ QTRY_COMPARE(m_view->selectedText(), QString("foo"));
}
}
@@ -2606,8 +2660,36 @@ Q_OBJECT
public:
GetUserMediaTestPage()
: m_gotRequest(false)
+ , m_loadSucceeded(false)
{
connect(this, &QWebEnginePage::featurePermissionRequested, this, &GetUserMediaTestPage::onFeaturePermissionRequested);
+ connect(this, &QWebEnginePage::loadFinished, [this](bool success){
+ m_loadSucceeded = success;
+ });
+ // We need to load content from a resource in order for the securityOrigin to be valid.
+ load(QUrl("qrc:///resources/content.html"));
+ }
+
+ void jsGetUserMedia(const QString & constraints)
+ {
+ evaluateJavaScriptSync(this,
+ QStringLiteral(
+ "var promiseFulfilled = false;"
+ "var promiseRejected = false;"
+ "navigator.mediaDevices.getUserMedia(%1)"
+ ".then(stream => { promiseFulfilled = true})"
+ ".catch(err => { promiseRejected = true})")
+ .arg(constraints));
+ }
+
+ bool jsPromiseFulfilled()
+ {
+ return evaluateJavaScriptSync(this, QStringLiteral("promiseFulfilled")).toBool();
+ }
+
+ bool jsPromiseRejected()
+ {
+ return evaluateJavaScriptSync(this, QStringLiteral("promiseRejected")).toBool();
}
void rejectPendingRequest()
@@ -2626,6 +2708,16 @@ public:
return m_gotRequest && m_requestedFeature == feature;
}
+ bool gotFeatureRequest() const
+ {
+ return m_gotRequest;
+ }
+
+ bool loadSucceeded() const
+ {
+ return m_loadSucceeded;
+ }
+
private Q_SLOTS:
void onFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature)
{
@@ -2636,33 +2728,92 @@ private Q_SLOTS:
private:
bool m_gotRequest;
+ bool m_loadSucceeded;
QWebEnginePage::Feature m_requestedFeature;
QUrl m_requestSecurityOrigin;
};
+void tst_QWebEnginePage::getUserMediaRequest_data()
+{
+ QTest::addColumn<QString>("constraints");
+ QTest::addColumn<QWebEnginePage::Feature>("feature");
+
+ QTest::addRow("device audio")
+ << "{audio: true}" << QWebEnginePage::MediaAudioCapture;
+ QTest::addRow("device video")
+ << "{video: true}" << QWebEnginePage::MediaVideoCapture;
+ QTest::addRow("device audio+video")
+ << "{audio: true, video: true}" << QWebEnginePage::MediaAudioVideoCapture;
+ QTest::addRow("desktop video")
+ << "{video: { mandatory: { chromeMediaSource: 'desktop' }}}"
+ << QWebEnginePage::DesktopVideoCapture;
+ QTest::addRow("desktop audio+video")
+ << "{audio: { mandatory: { chromeMediaSource: 'desktop' }}, video: { mandatory: { chromeMediaSource: 'desktop' }}}"
+ << QWebEnginePage::DesktopAudioVideoCapture;
+}
void tst_QWebEnginePage::getUserMediaRequest()
{
- GetUserMediaTestPage page;
+ QFETCH(QString, constraints);
+ QFETCH(QWebEnginePage::Feature, feature);
- // We need to load content from a resource in order for the securityOrigin to be valid.
- QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
- page.load(QUrl("qrc:///resources/content.html"));
- QTRY_COMPARE(loadSpy.count(), 1);
+ GetUserMediaTestPage page;
+ QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000);
+ page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
+
+ // 1. Rejecting request on C++ side should reject promise on JS side.
+ page.jsGetUserMedia(constraints);
+ QTRY_VERIFY(page.gotFeatureRequest(feature));
+ page.rejectPendingRequest();
+ QTRY_VERIFY(!page.jsPromiseFulfilled() && page.jsPromiseRejected());
+
+ // 2. Accepting request on C++ side should either fulfill or reject the
+ // Promise on JS side. Due to the potential lack of physical media devices
+ // deeper in the content layer we cannot guarantee that the promise will
+ // always be fulfilled, however in this case an error should be returned to
+ // JS instead of leaving the Promise in limbo.
+ page.jsGetUserMedia(constraints);
+ QTRY_VERIFY(page.gotFeatureRequest(feature));
+ page.acceptPendingRequest();
+ QTRY_VERIFY(page.jsPromiseFulfilled() || page.jsPromiseRejected());
- QVERIFY(evaluateJavaScriptSync(&page, QStringLiteral("!!navigator.webkitGetUserMedia")).toBool());
- evaluateJavaScriptSync(&page, QStringLiteral("navigator.webkitGetUserMedia({audio: true}, function() {}, function(){})"));
- QTRY_VERIFY(page.gotFeatureRequest(QWebEnginePage::MediaAudioCapture));
- // Might end up failing due to the lack of physical media devices deeper in the content layer, so the JS callback is not guaranteed to be called,
- // but at least we go through that code path, potentially uncovering failing assertions.
+ // 3. Media feature permissions are not remembered.
+ page.jsGetUserMedia(constraints);
+ QTRY_VERIFY(page.gotFeatureRequest(feature));
page.acceptPendingRequest();
+ QTRY_VERIFY(page.jsPromiseFulfilled() || page.jsPromiseRejected());
+}
- page.runJavaScript(QStringLiteral("errorCallbackCalled = false;"));
- evaluateJavaScriptSync(&page, QStringLiteral("navigator.webkitGetUserMedia({audio: true, video: true}, function() {}, function(){errorCallbackCalled = true;})"));
- QTRY_VERIFY(page.gotFeatureRequest(QWebEnginePage::MediaAudioVideoCapture));
- page.rejectPendingRequest(); // Should always end up calling the error callback in JS.
- QTRY_VERIFY(evaluateJavaScriptSync(&page, QStringLiteral("errorCallbackCalled;")).toBool());
+void tst_QWebEnginePage::getUserMediaRequestDesktopAudio()
+{
+ GetUserMediaTestPage page;
+ QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000);
+ page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
+
+ // Audio-only desktop capture is not supported. JS Promise should be
+ // rejected immediately.
+
+ page.jsGetUserMedia(
+ QStringLiteral("{audio: { mandatory: { chromeMediaSource: 'desktop' }}}"));
+ QTRY_VERIFY(!page.jsPromiseFulfilled() && page.jsPromiseRejected());
+
+ page.jsGetUserMedia(
+ QStringLiteral("{audio: { mandatory: { chromeMediaSource: 'desktop' }}, video: true}"));
+ QTRY_VERIFY(!page.jsPromiseFulfilled() && page.jsPromiseRejected());
+}
+
+void tst_QWebEnginePage::getUserMediaRequestSettingDisabled()
+{
+ GetUserMediaTestPage page;
+ QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000);
+ page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, false);
+
+ // With the setting disabled, the JS Promise should be rejected without
+ // asking for permission first.
+
+ page.jsGetUserMedia(QStringLiteral("{video: { mandatory: { chromeMediaSource: 'desktop' }}}"));
+ QTRY_VERIFY(!page.jsPromiseFulfilled() && page.jsPromiseRejected());
}
void tst_QWebEnginePage::savePage()
@@ -3044,21 +3195,19 @@ void tst_QWebEnginePage::progressSignal()
void tst_QWebEnginePage::urlChange()
{
- QSignalSpy urlSpy(m_page, SIGNAL(urlChanged(QUrl)));
+ QSignalSpy urlSpy(m_page, &QWebEnginePage::urlChanged);
QUrl dataUrl("data:text/html,<h1>Test");
m_view->setUrl(dataUrl);
- QVERIFY(urlSpy.wait());
-
- QCOMPARE(urlSpy.size(), 1);
+ QTRY_COMPARE(urlSpy.size(), 1);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), dataUrl);
QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>");
m_view->setUrl(dataUrl2);
- QVERIFY(urlSpy.wait());
-
- QCOMPARE(urlSpy.size(), 2);
+ QTRY_COMPARE(urlSpy.size(), 1);
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), dataUrl2);
}
class FakeReply : public QNetworkReply {
@@ -3169,7 +3318,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures()
page.load(second);
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 12000);
- QCOMPARE(page.url(), first);
+ QCOMPARE(page.url(), second);
QCOMPARE(page.requestedUrl(), second);
QVERIFY(!spy.at(1).first().toBool());
}
@@ -3410,7 +3559,7 @@ void tst_QWebEnginePage::scrollPosition()
view.setFixedSize(200,200);
view.show();
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QSignalSpy loadSpy(view.page(), SIGNAL(loadFinished(bool)));
view.setHtml(html);
@@ -3427,77 +3576,21 @@ void tst_QWebEnginePage::scrollPosition()
QCOMPARE(y, 29);
}
-void tst_QWebEnginePage::scrollToAnchor()
+void tst_QWebEnginePage::scrollbarsOff()
{
-#if !defined(QWEBENGINEELEMENT)
- QSKIP("QWEBENGINEELEMENT");
-#else
- QWebEnginePage page;
- page.setViewportSize(QSize(480, 800));
+ QWebEngineView view;
+ view.page()->settings()->setAttribute(QWebEngineSettings::ShowScrollBars, false);
- QString html("<html><body><p style=\"margin-bottom: 1500px;\">Hello.</p>"
- "<p><a id=\"foo\">This</a> is an anchor</p>"
- "<p style=\"margin-bottom: 1500px;\"><a id=\"bar\">This</a> is another anchor</p>"
+ QString html("<html><body>"
+ " <div style='margin-top:1000px ; margin-left:1000px'>"
+ " <a id='offscreen' href='a'>End</a>"
+ " </div>"
"</body></html>");
- page.setHtml(html);
- page.setScrollPosition(QPoint(0, 0));
- QCOMPARE(page.scrollPosition().x(), 0);
- QCOMPARE(page.scrollPosition().y(), 0);
-
- QWebEngineElement fooAnchor = page.findFirstElement("a[id=foo]");
- page.scrollToAnchor("foo");
- QCOMPARE(page.scrollPosition().y(), fooAnchor.geometry().top());
-
- page.scrollToAnchor("bar");
- page.scrollToAnchor("foo");
- QCOMPARE(page.scrollPosition().y(), fooAnchor.geometry().top());
-
- page.scrollToAnchor("top");
- QCOMPARE(page.scrollPosition().y(), 0);
-
- page.scrollToAnchor("bar");
- page.scrollToAnchor("notexist");
- QVERIFY(page.scrollPosition().y() != 0);
-#endif
-}
-
-
-void tst_QWebEnginePage::scrollbarsOff()
-{
-#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT)
- QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT");
-#else
- QWebEngineView view;
- QWebEngineFrame* mainFrame = view.page();
-
- mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
- mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
-
- QString html("<script>" \
- " function checkScrollbar() {" \
- " if (innerWidth === document.documentElement.offsetWidth)" \
- " document.getElementById('span1').innerText = 'SUCCESS';" \
- " else" \
- " document.getElementById('span1').innerText = 'FAIL';" \
- " }" \
- "</script>" \
- "<body>" \
- " <div style='margin-top:1000px ; margin-left:1000px'>" \
- " <a id='offscreen' href='a'>End</a>" \
- " </div>" \
- "<span id='span1'></span>" \
- "</body>");
-
-
- QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool)));
view.setHtml(html);
- QVERIFY(loadSpy.wait(200);
- QCOMPARE(loadSpy.count(), 1);
-
- mainFrame->evaluateJavaScript("checkScrollbar();");
- QCOMPARE(mainFrame->documentElement().findAll("span").at(0).toPlainText(), QString("SUCCESS"));
-#endif
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QVERIFY(evaluateJavaScriptSync(view.page(), "innerWidth == document.documentElement.offsetWidth").toBool());
}
void tst_QWebEnginePage::horizontalScrollAfterBack()
@@ -3545,7 +3638,7 @@ void tst_QWebEnginePage::evaluateWillCauseRepaint()
{
WebView view;
view.show();
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QString html("<html><body>"
" top"
@@ -3739,6 +3832,90 @@ void tst_QWebEnginePage::setUrlToInvalid()
QCOMPARE(baseUrlSync(&page), aboutBlank);
}
+void tst_QWebEnginePage::setUrlToBadDomain()
+{
+ // Failing to load a URL should still emit a urlChanged signal.
+ //
+ // This test is based on the scenario in QTBUG-48995 where the second setUrl
+ // call first triggers an unexpected additional urlChanged signal with the
+ // original url before the expected signal with the new url.
+
+ // RFC 2606 says the .invalid TLD should be invalid.
+ const QUrl url1 = QStringLiteral("http://this.is.definitely.invalid/");
+ const QUrl url2 = QStringLiteral("http://this.is.also.invalid/");
+ QWebEnginePage page;
+ QSignalSpy urlSpy(&page, &QWebEnginePage::urlChanged);
+ QSignalSpy titleSpy(&page, &QWebEnginePage::titleChanged);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+
+ page.setUrl(url1);
+
+ QTRY_COMPARE(urlSpy.count(), 1);
+ QTRY_COMPARE(titleSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url1);
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url1.host());
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
+
+ QCOMPARE(page.url(), url1);
+ QCOMPARE(page.title(), url1.host());
+
+ page.setUrl(url2);
+
+ QTRY_COMPARE(urlSpy.count(), 1);
+ QTRY_COMPARE(titleSpy.count(), 1);
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url2);
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url2.host());
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
+
+ QCOMPARE(page.url(), url2);
+ QCOMPARE(page.title(), url2.host());
+}
+
+void tst_QWebEnginePage::setUrlToBadPort()
+{
+ // Failing to load a URL should still emit a urlChanged signal.
+
+ // Ports 244-245 are hopefully unbound (marked unassigned in RFC1700).
+ const QUrl url1 = QStringLiteral("http://127.0.0.1:244/");
+ const QUrl url2 = QStringLiteral("http://127.0.0.1:245/");
+ QWebEnginePage page;
+ QSignalSpy urlSpy(&page, &QWebEnginePage::urlChanged);
+ QSignalSpy titleSpy(&page, &QWebEnginePage::titleChanged);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+
+ page.setUrl(url1);
+
+ QTRY_COMPARE(urlSpy.count(), 1);
+ QTRY_COMPARE(titleSpy.count(), 2);
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url1);
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url1.authority());
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url1.host());
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
+
+ QCOMPARE(page.url(), url1);
+ QCOMPARE(page.title(), url1.host());
+
+ page.setUrl(url2);
+
+ QTRY_COMPARE(urlSpy.count(), 1);
+ QTRY_COMPARE(titleSpy.count(), 2);
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url2);
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url2.authority());
+ QCOMPARE(titleSpy.takeFirst().value(0).toString(), url2.host());
+ QCOMPARE(loadSpy.takeFirst().value(0).toBool(), false);
+
+ QCOMPARE(page.url(), url2);
+ QCOMPARE(page.title(), url2.host());
+}
+
static QStringList collectHistoryUrls(QWebEngineHistory *history)
{
QStringList urls;
@@ -3899,9 +4076,8 @@ void tst_QWebEnginePage::setUrlThenLoads()
const QUrl urlToLoad1("qrc:/resources/test2.html");
const QUrl urlToLoad2("qrc:/resources/test1.html");
- // Just after first load. URL didn't changed yet.
m_page->load(urlToLoad1);
- QCOMPARE(m_page->url(), url);
+ QCOMPARE(m_page->url(), urlToLoad1);
QCOMPARE(m_page->requestedUrl(), urlToLoad1);
// baseUrlSync spins an event loop and this sometimes return the next result.
// QCOMPARE(baseUrlSync(m_page), baseUrl);
@@ -3915,9 +4091,8 @@ void tst_QWebEnginePage::setUrlThenLoads()
QCOMPARE(m_page->requestedUrl(), urlToLoad1);
QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1));
- // Just after second load. URL didn't changed yet.
m_page->load(urlToLoad2);
- QCOMPARE(m_page->url(), urlToLoad1);
+ QCOMPARE(m_page->url(), urlToLoad2);
QCOMPARE(m_page->requestedUrl(), urlToLoad2);
QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1));
QTRY_COMPARE(startedSpy.count(), 3);
@@ -4128,10 +4303,10 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace()
QVERIFY(s.contains("foobarbaz") == !enableErrorPage);
page->load(QUrl("data:text/plain,lalala"));
- QTRY_VERIFY(spy.count() == 3);
- QCOMPARE(toPlainTextSync(page.data()), QString("lalala"));
+ QTRY_COMPARE(spy.count(), 3);
+ QTRY_COMPARE(toPlainTextSync(page.data()), QString("lalala"));
page.reset();
- QVERIFY(spy.count() == 3);
+ QCOMPARE(spy.count(), 3);
}
void tst_QWebEnginePage::setZoomFactor()
@@ -4216,7 +4391,7 @@ void tst_QWebEnginePage::mouseButtonTranslation()
</div>\
</body></html>"));
view.show();
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QTRY_VERIFY(spy.count() == 1);
QVERIFY(view.focusProxy() != nullptr);
@@ -4240,7 +4415,7 @@ void tst_QWebEnginePage::mouseMovementProperties()
ConsolePage page;
view.setPage(&page);
view.show();
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
page.setHtml(QStringLiteral(
@@ -4372,5 +4547,7 @@ void tst_QWebEnginePage::proxyConfigWithUnexpectedHostPortPair()
QTRY_COMPARE(loadFinishedSpy.count(), 1);
}
-QTEST_MAIN(tst_QWebEnginePage)
+static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")};
+W_QTEST_MAIN(tst_QWebEnginePage, params)
+
#include "tst_qwebenginepage.moc"
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
index 1226e367d..fc83aefa5 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
@@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
+ <file>resources/basic_printing_page.html</file>
<file>resources/content.html</file>
<file>resources/index.html</file>
<file>resources/frame_a.html</file>
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 639a8456f..6961f3b6d 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -49,6 +49,7 @@ private Q_SLOTS:
void urlSchemeHandlers();
void urlSchemeHandlerFailRequest();
void urlSchemeHandlerFailOnRead();
+ void urlSchemeHandlerStreaming();
void customUserAgent();
void httpAcceptLanguage();
void downloadItem();
@@ -183,6 +184,80 @@ public:
QList<QPointer<QBuffer>> m_buffers;
};
+class StreamingIODevice : public QIODevice {
+ Q_OBJECT
+public:
+ StreamingIODevice(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0)
+ {
+ setOpenMode(QIODevice::ReadOnly);
+ m_timer.start(100, this);
+ }
+ void close() override
+ {
+ QMutexLocker lock(&m_mutex);
+ QIODevice::close();
+ deleteLater();
+ }
+ bool isSequential() const override { return true; }
+ qint64 bytesAvailable() const override
+ { return m_bytesAvailable; }
+ bool atEnd() const override
+ {
+ return (m_data.size() >= 1000 && m_bytesRead >= 1000);
+ }
+protected:
+ void timerEvent(QTimerEvent *) override
+ {
+ QMutexLocker lock(&m_mutex);
+ m_bytesAvailable += 200;
+ m_data.append(200, 'c');
+ emit readyRead();
+ if (m_data.size() >= 1000) {
+ m_timer.stop();
+ emit readChannelFinished();
+ }
+ }
+
+ qint64 readData(char *data, qint64 maxlen) override
+ {
+ QMutexLocker lock(&m_mutex);
+ qint64 len = qMin(qint64(m_bytesAvailable), maxlen);
+ if (len) {
+ memcpy(data, m_data.constData() + m_bytesRead, len);
+ m_bytesAvailable -= len;
+ m_bytesRead += len;
+ } else if (m_data.size() > 0)
+ return -1;
+
+ return len;
+ }
+ qint64 writeData(const char *, qint64) override
+ {
+ return 0;
+ }
+
+private:
+ QMutex m_mutex;
+ QByteArray m_data;
+ QBasicTimer m_timer;
+ int m_bytesRead;
+ int m_bytesAvailable;
+};
+
+class StreamingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
+{
+public:
+ StreamingUrlSchemeHandler(QObject *parent = nullptr)
+ : QWebEngineUrlSchemeHandler(parent)
+ {
+ }
+
+ void requestStarted(QWebEngineUrlRequestJob *job)
+ {
+ job->reply("text/plain;charset=utf-8", new StreamingIODevice(this));
+ }
+};
+
static bool loadSync(QWebEngineView *view, const QUrl &url, int timeout = 5000)
{
// Ripped off QTRY_VERIFY.
@@ -320,6 +395,22 @@ void tst_QWebEngineProfile::urlSchemeHandlerFailOnRead()
QCOMPARE(toPlainTextSync(view.page()), QString());
}
+void tst_QWebEngineProfile::urlSchemeHandlerStreaming()
+{
+ StreamingUrlSchemeHandler handler;
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("stream", &handler);
+ QWebEngineView view;
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.setPage(new QWebEnginePage(&profile, &view));
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ view.load(QUrl(QStringLiteral("stream://whatever")));
+ QVERIFY(loadFinishedSpy.wait());
+ QByteArray result;
+ result.append(1000, 'c');
+ QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result));
+}
+
void tst_QWebEngineProfile::customUserAgent()
{
QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent();
diff --git a/tests/auto/widgets/qwebenginescript/resources/test_iframe_inner.html b/tests/auto/widgets/qwebenginescript/resources/test_iframe_inner.html
new file mode 100644
index 000000000..3539c9620
--- /dev/null
+++ b/tests/auto/widgets/qwebenginescript/resources/test_iframe_inner.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+<div>Inner text</div>
+</body>
+</html>
diff --git a/tests/auto/widgets/qwebenginescript/resources/test_iframe_main.html b/tests/auto/widgets/qwebenginescript/resources/test_iframe_main.html
new file mode 100644
index 000000000..47b991c2c
--- /dev/null
+++ b/tests/auto/widgets/qwebenginescript/resources/test_iframe_main.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+<div>Main text</div>
+<iframe id="outer" src="qrc:/resources/test_iframe_outer.html"></iframe>
+</body>
+</html>
diff --git a/tests/auto/widgets/qwebenginescript/resources/test_iframe_outer.html b/tests/auto/widgets/qwebenginescript/resources/test_iframe_outer.html
new file mode 100644
index 000000000..8854809f8
--- /dev/null
+++ b/tests/auto/widgets/qwebenginescript/resources/test_iframe_outer.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+<div>Outer text</div>
+<iframe id="inner" src="qrc:/resources/test_iframe_inner.html"></iframe>
+</body>
+</html>
diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
index c10ae2886..d852ca902 100644
--- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
+++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
@@ -38,6 +38,7 @@ private Q_SLOTS:
void webChannel_data();
void webChannel();
void noTransportWithoutWebChannel();
+ void scriptsInNestedIframes();
};
void tst_QWebEngineScript::domEditing()
@@ -66,7 +67,7 @@ void tst_QWebEngineScript::domEditing()
QVERIFY(spyFinished.wait());
QCOMPARE(evaluateJavaScriptSync(&page, "document.getElementById(\"banner\").innerText"), QVariant(QStringLiteral("Injected banner")));
// elementFromPoint only works for exposed elements
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QCOMPARE(evaluateJavaScriptSync(&page, "document.elementFromPoint(2, 2).id"), QVariant::fromValue(QStringLiteral("banner")));
}
@@ -80,15 +81,12 @@ void tst_QWebEngineScript::injectionPoint()
s.setInjectionPoint(static_cast<QWebEngineScript::InjectionPoint>(injectionPoint));
s.setWorldId(QWebEngineScript::MainWorld);
QWebEnginePage page;
- page.scripts().insert(s);
- page.setHtml(QStringLiteral("<html><head><script> var contents;") + testScript
- + QStringLiteral("document.addEventListener(\"load\", setTimeout(function(event) {\
- document.body.innerText = contents;\
- }, 550));\
- </script></head><body></body></html>"));
QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+ page.scripts().insert(s);
+ page.setHtml(QStringLiteral("<html><head><script>") + testScript + QStringLiteral("</script></head><body></body></html>"));
QVERIFY(spyFinished.wait());
- QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS")));
+ const QVariant expected(QVariant::fromValue(QStringLiteral("SUCCESS")));
+ QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.myContents"), expected);
}
void tst_QWebEngineScript::injectionPoint_data()
@@ -96,17 +94,21 @@ void tst_QWebEngineScript::injectionPoint_data()
QTest::addColumn<int>("injectionPoint");
QTest::addColumn<QString>("testScript");
QTest::newRow("DocumentCreation") << static_cast<int>(QWebEngineScript::DocumentCreation)
- << QStringLiteral("var contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";");
+ << QStringLiteral("document.myContents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";");
QTest::newRow("DocumentReady") << static_cast<int>(QWebEngineScript::DocumentReady)
// use a zero timeout to make sure the user script got a chance to run as the order is undefined.
<< QStringLiteral("document.addEventListener(\"DOMContentLoaded\", function() {\
- setTimeout(function() {\
- contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\
- }, 0)});");
- QTest::newRow("Deferred") << static_cast<int>(QWebEngineScript::Deferred)
- << QStringLiteral("document.addEventListener(\"load\", setTimeout(function(event) {\
- contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\
- }, 500));");
+ setTimeout(function() {\
+ document.myContents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\
+ }, 0)});");
+ QTest::newRow("Deferred") << static_cast<int>(QWebEngineScript::DocumentReady)
+ << QStringLiteral("document.onreadystatechange = function() { \
+ if (document.readyState == \"complete\") { \
+ setTimeout(function() {\
+ document.myContents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\
+ }, 0);\
+ } \
+ };");
}
void tst_QWebEngineScript::scriptWorld()
@@ -246,6 +248,58 @@ void tst_QWebEngineScript::noTransportWithoutWebChannel()
QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid));
}
+void tst_QWebEngineScript::scriptsInNestedIframes()
+{
+ QWebEnginePage page;
+ QWebEngineView view;
+ view.setPage(&page);
+ QWebEngineScript s;
+ s.setInjectionPoint(QWebEngineScript::DocumentReady);
+ s.setWorldId(QWebEngineScript::ApplicationWorld);
+
+ // Prepend a "Modified prefix" to every frame's div content.
+ s.setSourceCode("var elements = document.getElementsByTagName(\"div\");\
+ var i;\
+ for (i = 0; i < elements.length; i++) {\
+ var content = elements[i].innerHTML;\
+ elements[i].innerHTML = \"Modified \" + content;\
+ }\
+ ");
+
+ // Make sure the script runs on all frames.
+ s.setRunsOnSubFrames(true);
+ page.scripts().insert(s);
+
+ QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished);
+ page.load(QUrl("qrc:/resources/test_iframe_main.html"));
+ view.show();
+ QVERIFY(spyFinished.wait());
+
+ // Check that main frame has modified content.
+ QCOMPARE(
+ evaluateJavaScriptSyncInWorld(&page, "document.getElementsByTagName(\"div\")[0].innerHTML",
+ QWebEngineScript::ApplicationWorld),
+ QVariant::fromValue(QStringLiteral("Modified Main text")));
+
+ // Check that outer frame has modified content.
+ QCOMPARE(
+ evaluateJavaScriptSyncInWorld(&page,
+ "var i = document.getElementById(\"outer\").contentDocument;\
+ i.getElementsByTagName(\"div\")[0].innerHTML",
+ QWebEngineScript::ApplicationWorld),
+ QVariant::fromValue(QStringLiteral("Modified Outer text")));
+
+
+ // Check that inner frame has modified content.
+ QCOMPARE(
+ evaluateJavaScriptSyncInWorld(&page,
+ "var i = document.getElementById(\"outer\").contentDocument;\
+ var i2 = i.getElementById(\"inner\").contentDocument;\
+ i2.getElementsByTagName(\"div\")[0].innerHTML",
+ QWebEngineScript::ApplicationWorld),
+ QVariant::fromValue(QStringLiteral("Modified Inner text")));
+}
+
QTEST_MAIN(tst_QWebEngineScript)
#include "tst_qwebenginescript.moc"
diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc
new file mode 100644
index 000000000..8b7a11cf2
--- /dev/null
+++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/test_iframe_main.html</file>
+ <file>resources/test_iframe_outer.html</file>
+ <file>resources/test_iframe_inner.html</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
index d8c18e509..5cbcf4ec0 100644
--- a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
+++ b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
@@ -33,6 +33,8 @@ private Q_SLOTS:
void tst_QWebEngineSettings::resetAttributes()
{
+ // QT_TODO_FIXME_ADAPT
+ QSKIP("The application deadlocks and hangs without exiting.");
QWebEngineProfile profile;
QWebEngineSettings *settings = profile.settings();
@@ -74,6 +76,8 @@ void tst_QWebEngineSettings::defaultFontFamily_data()
void tst_QWebEngineSettings::defaultFontFamily()
{
+ // QT_TODO_FIXME_ADAPT
+ QSKIP("The application deadlocks and hangs without exiting.");
QWebEngineProfile profile;
QWebEngineSettings *settings = profile.settings();
diff --git a/tests/auto/widgets/qwebenginehistoryinterface/qwebenginehistoryinterface.pro b/tests/auto/widgets/qwebengineshutdown/qwebengineshutdown.pro
index e99c7f493..e99c7f493 100644
--- a/tests/auto/widgets/qwebenginehistoryinterface/qwebenginehistoryinterface.pro
+++ b/tests/auto/widgets/qwebengineshutdown/qwebengineshutdown.pro
diff --git a/tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp b/tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp
new file mode 100644
index 000000000..d757e0d60
--- /dev/null
+++ b/tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qwebenginepage.h>
+#include <qwebengineview.h>
+#include <QDebug>
+
+class tst_QWebEngineShutdown : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebEngineShutdown();
+ virtual ~tst_QWebEngineShutdown();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private Q_SLOTS:
+ void dummyTest();
+
+private:
+
+
+private:
+ QWebEngineView* m_view;
+ QWebEnginePage* m_page;
+};
+
+tst_QWebEngineShutdown::tst_QWebEngineShutdown()
+{
+}
+
+tst_QWebEngineShutdown::~tst_QWebEngineShutdown()
+{
+}
+
+void tst_QWebEngineShutdown::init()
+{
+ m_view = new QWebEngineView();
+ m_page = m_view->page();
+}
+
+void tst_QWebEngineShutdown::cleanup()
+{
+ delete m_view;
+}
+
+void tst_QWebEngineShutdown::dummyTest()
+{
+ QVERIFY(m_view);
+}
+
+QTEST_MAIN(tst_QWebEngineShutdown)
+#include "tst_qwebengineshutdown.moc"
diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic b/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic
index d10ae2600..a57ab15b4 100644
--- a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic
+++ b/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic
@@ -8,6 +8,7 @@ liebe/Q
lieben/Q
liebst/Q
liebt/Q
+löwe/Q
qt/Q
sie/Q
Sie/Q
diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic
index 3d4ecdfa4..63e9164cc 100644
--- a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic
+++ b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic
@@ -4,6 +4,7 @@ I/Q
it/Q
love/Q
loves/Q
+low/Q
qt/Q
she/Q
they/Q
diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp
index c7b083660..4f14f29f9 100644
--- a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp
+++ b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp
@@ -32,6 +32,7 @@
#include <QtWebEngineWidgets/qwebengineprofile.h>
#include <QtWebEngineWidgets/qwebenginepage.h>
#include <QtWebEngineWidgets/qwebengineview.h>
+#include <qwebenginesettings.h>
class WebView : public QWebEngineView
{
@@ -143,24 +144,27 @@ void tst_QWebEngineSpellcheck::spellcheck()
QFETCH(QStringList, languages);
QFETCH(QStringList, suggestions);
+ m_view->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+
QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
QVERIFY(profile);
profile->setSpellCheckLanguages(languages);
profile->setSpellCheckEnabled(true);
load();
+ QCOMPARE(profile->spellCheckLanguages(), languages);
// make textarea editable
evaluateJavaScriptSync(m_view->page(), "makeEditable();");
// calcuate position of misspelled word
- QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lovee Qt ....','lovee');").toList();
+ QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lowe Qt ....','lowe');").toList();
QRect rect(list[0].value<int>(),list[1].value<int>(),list[2].value<int>(),list[3].value<int>());
//type text, spellchecker needs time
QTest::mouseMove(m_view->focusWidget(), QPoint(20,20));
QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20));
QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20));
- QString text("I lovee Qt ....");
+ QString text("I lowe Qt ....");
for (int i = 0; i < text.length(); i++) {
QTest::keyClicks(m_view->focusWidget(), text.at(i));
QTest::qWait(60);
@@ -180,10 +184,10 @@ void tst_QWebEngineSpellcheck::spellcheck()
QVERIFY(m_view->data().isContentEditable());
// check misspelled word
- QVERIFY(m_view->data().misspelledWord() == "lovee");
+ QCOMPARE(m_view->data().misspelledWord(), QStringLiteral("lowe"));
// check suggestions
- QVERIFY(m_view->data().spellCheckerSuggestions() == suggestions);
+ QCOMPARE(m_view->data().spellCheckerSuggestions(), suggestions);
// check replace word
m_view->page()->replaceMisspelledWord("love");
@@ -195,8 +199,8 @@ void tst_QWebEngineSpellcheck::spellcheck_data()
{
QTest::addColumn<QStringList>("languages");
QTest::addColumn<QStringList>("suggestions");
- QTest::newRow("en-US") << QStringList({"en-US"}) << QStringList({"love", "loves"});
- QTest::newRow("en-US,de-DE") << QStringList({"en-US","de-DE"}) << QStringList({"love", "liebe", "loves"});
+ QTest::newRow("en-US") << QStringList({"en-US"}) << QStringList({"low", "love"});
+ QTest::newRow("en-US,de-DE") << QStringList({"en-US", "de-DE"}) << QStringList({"low", "löwe", "love"});
}
QTEST_MAIN(tst_QWebEngineSpellcheck)
diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST
index b3f393af4..bf7292c86 100644
--- a/tests/auto/widgets/qwebengineview/BLACKLIST
+++ b/tests/auto/widgets/qwebengineview/BLACKLIST
@@ -1,8 +1,8 @@
[doNotSendMouseKeyboardEventsWhenDisabled]
windows
-[imeComposition]
-osx
+[mouseLeave]
+*
-[inputFieldOverridesShortcuts]
-osx
+[textSelectionOutOfInputField]
+*
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 04de4d951..34a6f245b 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -33,10 +33,12 @@
#include <qdiriterator.h>
#include <qstackedlayout.h>
#include <qtemporarydir.h>
+#include <QClipboard>
#include <QCompleter>
#include <QLabel>
#include <QLineEdit>
#include <QHBoxLayout>
+#include <QMenu>
#include <QQuickItem>
#include <QQuickWidget>
#include <QtWebEngineCore/qwebenginehttprequest.h>
@@ -92,6 +94,30 @@ static QRect elementGeometry(QWebEnginePage *page, const QString &id)
return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt());
}
+QT_BEGIN_NAMESPACE
+namespace QTest {
+ int Q_TESTLIB_EXPORT defaultMouseDelay();
+
+ static void mouseEvent(QEvent::Type type, QWidget *widget, const QPoint &pos)
+ {
+ QTest::qWait(QTest::defaultMouseDelay());
+ lastMouseTimestamp += QTest::defaultMouseDelay();
+ QMouseEvent me(type, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ me.setTimestamp(++lastMouseTimestamp);
+ QSpontaneKeyEvent::setSpontaneous(&me);
+ qApp->sendEvent(widget, &me);
+ }
+
+ static void mouseMultiClick(QWidget *widget, const QPoint pos, int clickCount)
+ {
+ for (int i = 0; i < clickCount; ++i) {
+ mouseEvent(QMouseEvent::MouseButtonPress, widget, pos);
+ mouseEvent(QMouseEvent::MouseButtonRelease, widget, pos);
+ }
+ lastMouseTimestamp += mouseDoubleClickInterval;
+ }
+}
+QT_END_NAMESPACE
class tst_QWebEngineView : public QObject
{
@@ -133,6 +159,7 @@ private Q_SLOTS:
void inputMethodsTextFormat();
void keyboardEvents();
void keyboardFocusAfterPopup();
+ void mouseClick();
void postData();
void inputFieldOverridesShortcuts();
@@ -148,6 +175,15 @@ private Q_SLOTS:
void newlineInTextarea();
void mouseLeave();
+
+#ifndef QT_NO_CLIPBOARD
+ void globalMouseSelection();
+#endif
+ void noContextMenu();
+ void contextMenu_data();
+ void contextMenu();
+ void webUIURLs_data();
+ void webUIURLs();
};
// This will be called before the first test function is executed.
@@ -247,14 +283,14 @@ void tst_QWebEngineView::reusePage()
}
view1->show();
- QTest::qWaitForWindowExposed(view1);
+ QVERIFY(QTest::qWaitForWindowExposed(view1));
delete view1;
QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view
QWebEngineView *view2 = new QWebEngineView;
view2->setPage(page.data());
view2->show(); // in Windowless mode, you should still be able to see the plugin here
- QTest::qWaitForWindowExposed(view2);
+ QVERIFY(QTest::qWaitForWindowExposed(view2));
delete view2;
delete page.data(); // must not crash
@@ -267,12 +303,12 @@ class WebViewCrashTest : public QObject {
Q_OBJECT
QWebEngineView* m_view;
public:
- bool m_executed;
+ bool m_invokedStop;
WebViewCrashTest(QWebEngineView* view)
: m_view(view)
- , m_executed(false)
+ , m_invokedStop(false)
{
view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int)));
}
@@ -280,10 +316,11 @@ public:
private Q_SLOTS:
void loading(int progress)
{
- if (progress > 1 && progress < 100) {
- QVERIFY(!m_executed);
+ qDebug() << "progress: " << progress;
+ if (progress > 0 && progress < 100) {
+ QVERIFY(!m_invokedStop);
m_view->stop();
- m_executed = true;
+ m_invokedStop = true;
}
}
};
@@ -298,14 +335,17 @@ void tst_QWebEngineView::crashTests()
WebViewCrashTest tester(&view);
QUrl url("qrc:///resources/index.html");
view.load(url);
- QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed.
+
+ // If the verification fails, it means that either stopping doesn't work, or the hardware is
+ // too slow to load the page and thus to slow to issue the first loadProgress > 0 signal.
+ QTRY_VERIFY_WITH_TIMEOUT(tester.m_invokedStop, 10000);
}
void tst_QWebEngineView::microFocusCoordinates()
{
QWebEngineView webView;
webView.show();
- QTest::qWaitForWindowExposed(&webView);
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
QSignalSpy scrollSpy(webView.page(), SIGNAL(scrollPositionChanged(QPointF)));
QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool)));
@@ -334,27 +374,38 @@ void tst_QWebEngineView::microFocusCoordinates()
void tst_QWebEngineView::focusInputTypes()
{
+ const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
+ bool imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability);
+
QWebEngineView webView;
webView.show();
- QTest::qWaitForWindowExposed(&webView);
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool)));
webView.load(QUrl("qrc:///resources/input_types.html"));
QVERIFY(loadFinishedSpy.wait());
+ auto inputMethodQuery = [&webView](Qt::InputMethodQuery query) {
+ QInputMethodQueryEvent event(query);
+ QApplication::sendEvent(webView.focusProxy(), &event);
+ return event.value(query);
+ };
+
// 'text' field
QPoint textInputCenter = elementCenter(webView.page(), "textInput");
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'password' field
QPoint passwordInputCenter = elementCenter(webView.page(), "passwordInput");
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
- QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability);
// 'tel' field
QPoint telInputCenter = elementCenter(webView.page(), "telInput");
@@ -362,6 +413,7 @@ void tst_QWebEngineView::focusInputTypes()
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("telInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDialableCharactersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'number' field
QPoint numberInputCenter = elementCenter(webView.page(), "numberInput");
@@ -369,6 +421,7 @@ void tst_QWebEngineView::focusInputTypes()
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("numberInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'email' field
QPoint emailInputCenter = elementCenter(webView.page(), "emailInput");
@@ -376,6 +429,7 @@ void tst_QWebEngineView::focusInputTypes()
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("emailInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'url' field
QPoint urlInputCenter = elementCenter(webView.page(), "urlInput");
@@ -383,24 +437,28 @@ void tst_QWebEngineView::focusInputTypes()
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("urlInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase));
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'password' field
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
- QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability);
// 'text' type
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'password' field
QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
- QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability);
// 'text area' field
QPoint textAreaCenter = elementCenter(webView.page(), "textArea");
@@ -408,6 +466,7 @@ void tst_QWebEngineView::focusInputTypes()
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textArea"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhMultiLine | Qt::ImhPreferLowercase));
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
}
class KeyEventRecordingWidget : public QWidget {
@@ -423,7 +482,7 @@ void tst_QWebEngineView::unhandledKeyEventPropagation()
KeyEventRecordingWidget parentWidget;
QWebEngineView webView(&parentWidget);
parentWidget.show();
- QTest::qWaitForWindowExposed(&webView);
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool)));
webView.load(QUrl("qrc:///resources/keyboardEvents.html"));
@@ -481,7 +540,7 @@ void tst_QWebEngineView::horizontalScrollbarTest()
view.setFixedSize(600, 600);
view.show();
- QTest::qWaitForWindowExposed(&view);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QSignalSpy loadSpy(view.page(), SIGNAL(loadFinished(bool)));
view.setHtml(html);
@@ -771,7 +830,7 @@ void tst_QWebEngineView::doNotSendMouseKeyboardEventsWhenDisabled()
parentWidget.layout()->addWidget(&webView);
webView.resize(640, 480);
parentWidget.show();
- QTest::qWaitForWindowExposed(&webView);
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
webView.setHtml("<html><head><title>Title</title></head><body>Hello"
@@ -817,7 +876,7 @@ void tst_QWebEngineView::stopSettingFocusWhenDisabled()
webView.resize(640, 480);
webView.show();
webView.setEnabled(viewEnabled);
- QTest::qWaitForWindowExposed(&webView);
+ QVERIFY(QTest::qWaitForWindowExposed(&webView));
QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
webView.setHtml("<html><head><title>Title</title></head><body>Hello"
@@ -877,7 +936,7 @@ void tst_QWebEngineView::focusOnNavigation()
containerWidget->setLayout(layout);
containerWidget->show();
- QTest::qWaitForWindowExposed(containerWidget.data());
+ QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data()));
// Load the content, invoke javascript focus on the view, and check which widget has focus.
QSignalSpy loadSpy(webView, SIGNAL(loadFinished(bool)));
@@ -943,7 +1002,7 @@ void tst_QWebEngineView::focusInternalRenderWidgetHostViewQuickItem()
containerWidget->setLayout(layout);
containerWidget->show();
- QTest::qWaitForWindowExposed(containerWidget.data());
+ QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data()));
// Load the content, and check that focus is not set.
QSignalSpy loadSpy(webView, SIGNAL(loadFinished(bool)));
@@ -1041,6 +1100,7 @@ void tst_QWebEngineView::inputMethodsTextFormat_data()
void tst_QWebEngineView::inputMethodsTextFormat()
{
QWebEngineView view;
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
view.setHtml("<html><body>"
@@ -1179,6 +1239,7 @@ void tst_QWebEngineView::keyboardFocusAfterPopup()
urlLine->setFocus();
QWebEngineView *webView = new QWebEngineView(containerWidget.data());
+ webView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
QSignalSpy loadFinishedSpy(webView, SIGNAL(loadFinished(bool)));
connect(urlLine, &QLineEdit::editingFinished, [=] {
@@ -1201,7 +1262,7 @@ void tst_QWebEngineView::keyboardFocusAfterPopup()
containerWidget->setLayout(layout);
containerWidget->show();
- QTest::qWaitForWindowExposed(containerWidget.data());
+ QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data()));
// Trigger completer's popup and select the first suggestion
QTest::keyClick(urlLine, Qt::Key_T);
@@ -1221,6 +1282,76 @@ void tst_QWebEngineView::keyboardFocusAfterPopup()
QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').value").toString(), QStringLiteral("x"));
}
+void tst_QWebEngineView::mouseClick()
+{
+ QWebEngineView view;
+ view.show();
+ view.resize(200, 200);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
+ QPoint textInputCenter;
+
+ // Single Click
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+ selectionChangedSpy.clear();
+
+ view.setHtml("<html><body>"
+ "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ textInputCenter = elementCenter(view.page(), "input");
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QCOMPARE(selectionChangedSpy.count(), 0);
+ QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
+
+ // Double click
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+ selectionChangedSpy.clear();
+
+ view.setHtml("<html><body onload='document.getElementById(\"input\").focus()'>"
+ "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ textInputCenter = elementCenter(view.page(), "input");
+ QTest::mouseMultiClick(view.focusProxy(), textInputCenter, 2);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("Company"));
+
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 2);
+ QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
+
+ // Triple click
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+ selectionChangedSpy.clear();
+
+ view.setHtml("<html><body onload='document.getElementById(\"input\").focus()'>"
+ "<form><input id='input' width='150' type='text' value='The Qt Company' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ textInputCenter = elementCenter(view.page(), "input");
+ QTest::mouseMultiClick(view.focusProxy(), textInputCenter, 3);
+ QVERIFY(selectionChangedSpy.wait());
+ QTRY_COMPARE(selectionChangedSpy.count(), 2);
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("The Qt Company"));
+
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 3);
+ QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
+}
+
void tst_QWebEngineView::postData()
{
QMap<QString, QString> postData;
@@ -1362,18 +1493,18 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts()
view.addAction(action);
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
- view.setHtml(QString("<html><body onload=\"input1=document.getElementById('input1')\">"
+ view.setHtml(QString("<html><body>"
"<button id=\"btn1\" type=\"button\">push it real good</button>"
"<input id=\"input1\" type=\"text\" value=\"x\">"
"</body></html>"));
QVERIFY(loadFinishedSpy.wait());
view.show();
- QTest::qWaitForWindowActive(&view);
+ QVERIFY(QTest::qWaitForWindowActive(&view));
auto inputFieldValue = [&view] () -> QString {
return evaluateJavaScriptSync(view.page(),
- "input1.value").toString();
+ "document.getElementById('input1').value").toString();
};
// The input form is not focused. The action is triggered on pressing Shift+Delete.
@@ -1390,10 +1521,13 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts()
QCOMPARE(inputFieldValue(), QString("x"));
// The input form is focused. The action is not triggered, and the form's text changed.
- evaluateJavaScriptSync(view.page(), "input1.focus();");
+ evaluateJavaScriptSync(view.page(), "document.getElementById('input1').focus();");
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
actionTriggered = false;
QTest::keyClick(view.windowHandle(), Qt::Key_Y);
QTRY_COMPARE(inputFieldValue(), QString("yx"));
+ QTest::keyClick(view.windowHandle(), Qt::Key_X);
+ QTRY_COMPARE(inputFieldValue(), QString("yxx"));
QVERIFY(!actionTriggered);
// The input form is focused. Make sure we don't override all short cuts.
@@ -1401,10 +1535,20 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts()
action->setShortcut(Qt::CTRL + Qt::Key_1);
QTest::keyClick(view.windowHandle(), Qt::Key_1, Qt::ControlModifier);
QTRY_VERIFY(actionTriggered);
- QCOMPARE(inputFieldValue(), QString("yx"));
+ QCOMPARE(inputFieldValue(), QString("yxx"));
+
+ // The input form is focused. The following shortcuts are not overridden
+ // thus handled by Qt WebEngine. Make sure the subsequent shortcuts with text
+ // character don't cause assert due to an unconsumed editor command.
+ QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
+ QTest::keyClick(view.windowHandle(), Qt::Key_C, Qt::ControlModifier);
+ QTest::keyClick(view.windowHandle(), Qt::Key_V, Qt::ControlModifier);
+ QTest::keyClick(view.windowHandle(), Qt::Key_V, Qt::ControlModifier);
+ QTRY_COMPARE(inputFieldValue(), QString("yxxyxx"));
// Remove focus from the input field. A QKeySequence::Copy action must be triggerable.
evaluateJavaScriptSync(view.page(), "document.getElementById('btn1').focus();");
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("btn1"));
action->setShortcut(QKeySequence::Copy);
actionTriggered = false;
QTest::keyClick(view.windowHandle(), Qt::Key_C, Qt::ControlModifier);
@@ -1511,7 +1655,7 @@ void tst_QWebEngineView::inputMethods()
view.setHtml("<html><body>"
" <input type='text' id='input1' style='font-family: serif' value='' maxlength='20' size='50'/>"
"</body></html>");
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE(loadFinishedSpy.size(), 1);
QPoint textInputCenter = elementCenter(view.page(), "input1");
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
@@ -1557,8 +1701,7 @@ void tst_QWebEngineView::inputMethods()
QInputMethodEvent eventSelection1("", inputAttributes);
QApplication::sendEvent(view.focusProxy(), &eventSelection1);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 3);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 5);
@@ -1569,8 +1712,7 @@ void tst_QWebEngineView::inputMethods()
inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant());
QInputMethodEvent eventSelection2("", inputAttributes);
QApplication::sendEvent(view.focusProxy(), &eventSelection2);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 2);
+ QTRY_COMPARE(selectionChangedSpy.size(), 2);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 6);
@@ -1583,8 +1725,7 @@ void tst_QWebEngineView::inputMethods()
attributes.append(newSelection);
QInputMethodEvent eventComposition("composition", attributes);
QApplication::sendEvent(view.focusProxy(), &eventComposition);
- QVERIFY(selectionChangedSpy.wait());
- QCOMPARE(selectionChangedSpy.count(), 3);
+ QTRY_COMPARE(selectionChangedSpy.size(), 3);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
// An ongoing composition should not change the surrounding text before it is committed.
@@ -1628,14 +1769,17 @@ void tst_QWebEngineView::textSelectionInInputField()
event.setCommitString("XXX", 0, 0);
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineXXX"));
+ QCOMPARE(selectionChangedSpy.count(), 0);
event.setCommitString(QString(), -2, 2); // Erase two characters.
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineX"));
+ QCOMPARE(selectionChangedSpy.count(), 0);
event.setCommitString(QString(), -1, 1); // Erase one character.
QApplication::sendEvent(view.focusProxy(), &event);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine"));
+ QCOMPARE(selectionChangedSpy.count(), 0);
// Move to the start of the line
QTest::keyClick(view.focusProxy(), Qt::Key_Home);
@@ -1699,13 +1843,8 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
- // Workaround for macOS: press ctrl+a without key text
- QKeyEvent keyPressCtrlA(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier);
- QKeyEvent keyReleaseCtrlA(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier);
-
// Select text by ctrl+a
- QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA);
- QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA);
+ QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 1);
QVERIFY(view.hasSelection());
@@ -1735,8 +1874,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
// Select the whole page by ctrl+a
- QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA);
- QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA);
+ QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 1);
QVERIFY(view.hasSelection());
@@ -1752,8 +1890,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QVERIFY(view.page()->selectedText().isEmpty());
// Select the content of the input field by ctrl+a
- QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA);
- QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA);
+ QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 3);
QVERIFY(view.hasSelection());
@@ -1783,7 +1920,7 @@ void tst_QWebEngineView::hiddenText()
QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("password1"));
- QVERIFY(view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
+ QVERIFY(!view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
QVERIFY(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText);
QPoint textInputCenter = elementCenter(view.page(), "input1");
@@ -1805,19 +1942,13 @@ void tst_QWebEngineView::emptyInputMethodEvent()
QVERIFY(loadFinishedSpy.wait());
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
- QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty());
-
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QVERIFY(selectionChangedSpy.wait(100));
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
// 1. Empty input method event does not clear text
QInputMethodEvent emptyEvent;
- QApplication::sendEvent(view.focusProxy(), &emptyEvent);
-
- QString inputValue = evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString();
- QTRY_COMPARE(inputValue, QStringLiteral("QtWebEngine"));
+ QVERIFY(QApplication::sendEvent(view.focusProxy(), &emptyEvent));
+ qApp->processEvents();
+ QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("QtWebEngine"));
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QStringLiteral("QtWebEngine"));
// Reset: clear input field
@@ -1829,12 +1960,12 @@ void tst_QWebEngineView::emptyInputMethodEvent()
// Start IME composition
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent eventComposition("a", attributes);
- QApplication::sendEvent(view.focusProxy(), &eventComposition);
+ QVERIFY(QApplication::sendEvent(view.focusProxy(), &eventComposition));
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("a"));
QTRY_VERIFY(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString().isEmpty());
// Cancel IME composition
- QApplication::sendEvent(view.focusProxy(), &emptyEvent);
+ QVERIFY(QApplication::sendEvent(view.focusProxy(), &emptyEvent));
QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty());
QTRY_VERIFY(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString().isEmpty());
@@ -1857,12 +1988,7 @@ void tst_QWebEngineView::imeComposition()
QVERIFY(loadFinishedSpy.wait());
evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
- QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty());
-
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QVERIFY(selectionChangedSpy.wait(100));
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
// Clear the selection, also cancel the ongoing composition if there is one.
{
@@ -1871,17 +1997,13 @@ void tst_QWebEngineView::imeComposition()
attributes.append(newSelection);
QInputMethodEvent event("", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
- QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty());
-
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QVERIFY(selectionChangedSpy.wait(100));
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
+ selectionChangedSpy.wait();
QCOMPARE(selectionChangedSpy.count(), 2);
}
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod"));
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod"));
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
selectionChangedSpy.clear();
@@ -2002,19 +2124,14 @@ void tst_QWebEngineView::imeComposition()
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent event("w", attributes);
QApplication::sendEvent(view.focusProxy(), &event);
- QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty());
- QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("oeQtWebEngine w"));
-
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QVERIFY(selectionChangedSpy.wait(100));
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
+ // The new composition should clear the previous selection
+ QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 2);
}
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine "));
- QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 14);
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
- QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 14);
- QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine "));
+ // The cursor should be positioned at the end of the composition text
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 15);
+ QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 15);
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
// Send commit text, which makes the editor conforms composition.
@@ -2029,6 +2146,7 @@ void tst_QWebEngineView::imeComposition()
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 15);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 15);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString(""));
+ QCOMPARE(selectionChangedSpy.count(), 2);
}
void tst_QWebEngineView::newlineInTextarea()
@@ -2141,6 +2259,8 @@ void tst_QWebEngineView::imeCompositionQueryEvent_data()
void tst_QWebEngineView::imeCompositionQueryEvent()
{
QWebEngineView view;
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+
view.show();
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
@@ -2210,6 +2330,104 @@ void tst_QWebEngineView::imeCompositionQueryEvent()
QTRY_COMPARE(anchorPosQuery.value(Qt::ImAnchorPosition).toInt(), 11);
}
+#ifndef QT_NO_CLIPBOARD
+void tst_QWebEngineView::globalMouseSelection()
+{
+ if (!QApplication::clipboard()->supportsSelection()) {
+ QSKIP("Test only relevant for systems with selection");
+ return;
+ }
+
+ QApplication::clipboard()->clear(QClipboard::Selection);
+ QWebEngineView view;
+ view.show();
+
+ QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.setHtml("<html><body>"
+ " <input type='text' id='input1' value='QtWebEngine' size='50' />"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ // Select text via JavaScript
+ evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();");
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty());
+
+ // Deselect the selection (this moves the current cursor to the end of the text)
+ QPoint textInputCenter = elementCenter(view.page(), "input1");
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 2);
+ QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty());
+
+ // Select to the start of the line
+ QTest::keyClick(view.focusProxy(), Qt::Key_Home, Qt::ShiftModifier);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 3);
+ QCOMPARE(QApplication::clipboard()->text(QClipboard::Selection), QStringLiteral("QtWebEngine"));
+}
+#endif
+
+void tst_QWebEngineView::noContextMenu()
+{
+ QWidget wrapper;
+ wrapper.setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(&wrapper, &QWidget::customContextMenuRequested, [&wrapper](const QPoint &pt) {
+ QMenu* menu = new QMenu(&wrapper);
+ menu->addAction("Action1");
+ menu->addAction("Action2");
+ menu->popup(pt);
+ });
+
+ QWebEngineView view(&wrapper);
+ view.setContextMenuPolicy(Qt::NoContextMenu);
+ wrapper.show();
+
+ QVERIFY(view.findChildren<QMenu *>().isEmpty());
+ QVERIFY(wrapper.findChildren<QMenu *>().isEmpty());
+ QTest::mouseMove(wrapper.windowHandle(), QPoint(10,10));
+ QTest::mouseClick(wrapper.windowHandle(), Qt::RightButton);
+
+ QTRY_COMPARE(wrapper.findChildren<QMenu *>().count(), 1);
+ QVERIFY(view.findChildren<QMenu *>().isEmpty());
+}
+
+void tst_QWebEngineView::contextMenu_data()
+{
+ QTest::addColumn<int>("childrenCount");
+ QTest::addColumn<Qt::ContextMenuPolicy>("contextMenuPolicy");
+ QTest::newRow("defaultContextMenu") << 1 << Qt::DefaultContextMenu;
+ QTest::newRow("customContextMenu") << 1 << Qt::CustomContextMenu;
+ QTest::newRow("preventContextMenu") << 0 << Qt::PreventContextMenu;
+}
+
+void tst_QWebEngineView::contextMenu()
+{
+ QFETCH(int, childrenCount);
+ QFETCH(Qt::ContextMenuPolicy, contextMenuPolicy);
+
+ QWebEngineView view;
+
+ if (contextMenuPolicy == Qt::CustomContextMenu) {
+ connect(&view, &QWebEngineView::customContextMenuRequested, [&view](const QPoint &pt) {
+ QMenu* menu = new QMenu(&view);
+ menu->addAction("Action1");
+ menu->addAction("Action2");
+ menu->popup(pt);
+ });
+ }
+
+ view.setContextMenuPolicy(contextMenuPolicy);
+ view.show();
+
+ QVERIFY(view.findChildren<QMenu *>().isEmpty());
+ QTest::mouseMove(view.windowHandle(), QPoint(10,10));
+ QTest::mouseClick(view.windowHandle(), Qt::RightButton);
+ QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount);
+}
+
void tst_QWebEngineView::mouseLeave()
{
QScopedPointer<QWidget> containerWidget(new QWidget);
@@ -2252,7 +2470,9 @@ void tst_QWebEngineView::mouseLeave()
"</body>"
"</html>");
QVERIFY(loadFinishedSpy.wait());
- QVERIFY(innerText().isEmpty());
+ // Make sure the testDiv text is empty.
+ evaluateJavaScriptSync(view->page(), "document.getElementById('testDiv').innerText = ''");
+ QTRY_VERIFY(innerText().isEmpty());
QTest::mouseMove(containerWidget->windowHandle(), QPoint(50, 150));
QTRY_COMPARE(innerText(), QStringLiteral("Mouse IN"));
@@ -2260,5 +2480,89 @@ void tst_QWebEngineView::mouseLeave()
QTRY_COMPARE(innerText(), QStringLiteral("Mouse OUT"));
}
+void tst_QWebEngineView::webUIURLs_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<bool>("supported");
+ QTest::newRow("about") << QUrl("chrome://about") << false;
+ QTest::newRow("accessibility") << QUrl("chrome://accessibility") << false;
+ QTest::newRow("appcache-internals") << QUrl("chrome://appcache-internals") << true;
+ QTest::newRow("apps") << QUrl("chrome://apps") << false;
+ QTest::newRow("blob-internals") << QUrl("chrome://blob-internals") << true;
+ QTest::newRow("bluetooth-internals") << QUrl("chrome://bluetooth-internals") << false;
+ QTest::newRow("bookmarks") << QUrl("chrome://bookmarks") << false;
+ QTest::newRow("cache") << QUrl("chrome://cache") << false;
+ QTest::newRow("chrome") << QUrl("chrome://chrome") << false;
+ QTest::newRow("chrome-urls") << QUrl("chrome://chrome-urls") << false;
+ QTest::newRow("components") << QUrl("chrome://components") << false;
+ QTest::newRow("crashes") << QUrl("chrome://crashes") << false;
+ QTest::newRow("credits") << QUrl("chrome://credits") << false;
+ QTest::newRow("device-log") << QUrl("chrome://device-log") << false;
+ QTest::newRow("devices") << QUrl("chrome://devices") << false;
+ QTest::newRow("dino") << QUrl("chrome://dino") << false; // It works but this is an error page
+ QTest::newRow("dns") << QUrl("chrome://dns") << false;
+ QTest::newRow("downloads") << QUrl("chrome://downloads") << false;
+ QTest::newRow("extensions") << QUrl("chrome://extensions") << false;
+ QTest::newRow("flags") << QUrl("chrome://flags") << false;
+ QTest::newRow("flash") << QUrl("chrome://flash") << false;
+ QTest::newRow("gcm-internals") << QUrl("chrome://gcm-internals") << false;
+ QTest::newRow("gpu") << QUrl("chrome://gpu") << true;
+ QTest::newRow("help") << QUrl("chrome://help") << false;
+ QTest::newRow("histograms") << QUrl("chrome://histograms") << true;
+ QTest::newRow("indexeddb-internals") << QUrl("chrome://indexeddb-internals") << true;
+ QTest::newRow("inspect") << QUrl("chrome://inspect") << false;
+ QTest::newRow("invalidations") << QUrl("chrome://invalidations") << false;
+ QTest::newRow("linux-proxy-config") << QUrl("chrome://linux-proxy-config") << false;
+ QTest::newRow("local-state") << QUrl("chrome://local-state") << false;
+ QTest::newRow("media-internals") << QUrl("chrome://media-internals") << true;
+ QTest::newRow("net-export") << QUrl("chrome://net-export") << false;
+ QTest::newRow("net-internals") << QUrl("chrome://net-internals") << false;
+ QTest::newRow("network-error") << QUrl("chrome://network-error") << false;
+ QTest::newRow("network-errors") << QUrl("chrome://network-errors") << true;
+ QTest::newRow("newtab") << QUrl("chrome://newtab") << false;
+ QTest::newRow("ntp-tiles-internals") << QUrl("chrome://ntp-tiles-internals") << false;
+ QTest::newRow("omnibox") << QUrl("chrome://omnibox") << false;
+ QTest::newRow("password-manager-internals") << QUrl("chrome://password-manager-internals") << false;
+ QTest::newRow("policy") << QUrl("chrome://policy") << false;
+ QTest::newRow("predictors") << QUrl("chrome://predictors") << false;
+ QTest::newRow("print") << QUrl("chrome://print") << false;
+ QTest::newRow("profiler") << QUrl("chrome://profiler") << false;
+ QTest::newRow("quota-internals") << QUrl("chrome://quota-internals") << false;
+ QTest::newRow("safe-browsing") << QUrl("chrome://safe-browsing") << false;
+ QTest::newRow("sandbox") << QUrl("chrome://sandbox") << false;
+ QTest::newRow("serviceworker-internals") << QUrl("chrome://serviceworker-internals") << true;
+ QTest::newRow("settings") << QUrl("chrome://settings") << false;
+ QTest::newRow("signin-internals") << QUrl("chrome://signin-internals") << false;
+ QTest::newRow("site-engagement") << QUrl("chrome://site-engagement") << false;
+ QTest::newRow("suggestions") << QUrl("chrome://suggestions") << false;
+ QTest::newRow("supervised-user-internals") << QUrl("chrome://supervised-user-internals") << false;
+ QTest::newRow("sync-internals") << QUrl("chrome://sync-internals") << false;
+ QTest::newRow("system") << QUrl("chrome://system") << false;
+ QTest::newRow("taskscheduler-internals") << QUrl("chrome://taskscheduler-internals") << false;
+ QTest::newRow("terms") << QUrl("chrome://terms") << false;
+ QTest::newRow("thumbnails") << QUrl("chrome://thumbnails") << false;
+ QTest::newRow("tracing") << QUrl("chrome://tracing") << false;
+ QTest::newRow("translate-internals") << QUrl("chrome://translate-internals") << false;
+ QTest::newRow("usb-internals") << QUrl("chrome://usb-internals") << false;
+ QTest::newRow("user-actions") << QUrl("chrome://user-actions") << false;
+ QTest::newRow("version") << QUrl("chrome://version") << false;
+ QTest::newRow("view-http-cache") << QUrl("chrome://view-http-cache") << true;
+ QTest::newRow("webrtc-internals") << QUrl("chrome://webrtc-internals") << true;
+ QTest::newRow("webrtc-logs") << QUrl("chrome://webrtc-logs") << false;
+}
+
+void tst_QWebEngineView::webUIURLs()
+{
+ QFETCH(QUrl, url);
+ QFETCH(bool, supported);
+
+ QWebEngineView view;
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.load(url);
+ QVERIFY(loadFinishedSpy.wait());
+ QCOMPARE(loadFinishedSpy.takeFirst().at(0).toBool(), supported);
+}
+
QTEST_MAIN(tst_QWebEngineView)
#include "tst_qwebengineview.moc"
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
index 4809bbebf..53b11bca8 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
@@ -4,7 +4,6 @@
<file>resources/frame_a.html</file>
<file>resources/input_types.html</file>
<file>resources/scrolltest_page.html</file>
- <file>resources/basic_printing_page.html</file>
<file>resources/keyboardEvents.html</file>
</qresource>
</RCC>
diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri
index d77cd5af5..7bd00834c 100644
--- a/tests/auto/widgets/tests.pri
+++ b/tests/auto/widgets/tests.pri
@@ -1,3 +1,5 @@
+QT_FOR_CONFIG += webengine-private
+
TEMPLATE = app
CONFIG += testcase
diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h
index 356cf6ebb..ab3b9e6b9 100644
--- a/tests/auto/widgets/util.h
+++ b/tests/auto/widgets/util.h
@@ -67,15 +67,16 @@ public:
};
template<typename T, typename R>
-struct RefWrapper {
- R &ref;
+struct CallbackWrapper {
+ QPointer<R> p;
void operator()(const T& result) {
- ref(result);
+ if (p)
+ (*p)(result);
}
};
template<typename T>
-class CallbackSpy {
+class CallbackSpy: public QObject {
public:
CallbackSpy() : called(false) {
timeoutTimer.setSingleShot(true);
@@ -100,10 +101,9 @@ public:
eventLoop.quit();
}
- // Cheap rip-off of boost/std::ref
- RefWrapper<T, CallbackSpy<T> > ref()
+ CallbackWrapper<T, CallbackSpy<T> > ref()
{
- RefWrapper<T, CallbackSpy<T> > wrapper = {*this};
+ CallbackWrapper<T, CallbackSpy<T> > wrapper = {this};
return wrapper;
}
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
index 7bab18f00..c414e99f2 100644
--- a/tests/auto/widgets/widgets.pro
+++ b/tests/auto/widgets/widgets.pro
@@ -1,3 +1,5 @@
+QT_FOR_CONFIG += webengine
+
TEMPLATE = subdirs
SUBDIRS += \
@@ -6,19 +8,19 @@ SUBDIRS += \
qwebenginefaviconmanager \
qwebenginepage \
qwebenginehistory \
- qwebenginehistoryinterface \
qwebengineinspector \
qwebengineprofile \
qwebenginescript \
qwebenginesettings \
+ qwebengineshutdown \
qwebengineview
qtConfig(accessibility) {
SUBDIRS += qwebengineaccessibility
}
-contains(WEBENGINE_CONFIG, use_spellchecker):!cross_compile {
- !contains(WEBENGINE_CONFIG, use_native_spellchecker) {
+qtConfig(webengine-spellchecker):!cross_compile {
+ !qtConfig(webengine-native-spellchecker) {
SUBDIRS += qwebenginespellcheck
} else {
message("Spellcheck test will not be built because it depends on usage of Hunspell dictionaries.")