diff --git a/tests/auto/widgets/qwebenginescript/resources/test_window_open.html b/tests/auto/widgets/qwebenginescript/resources/test_window_open.html new file mode 100644 index 0000000000000000000000000000000000000000..3f72d176de1d2375a52fd0e2159b57de67f9b081 --- /dev/null +++ b/tests/auto/widgets/qwebenginescript/resources/test_window_open.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <title>window.open</title> + <script> + window.open("qrc:/resource/test_iframe_main.html", "iframe_main"); + </script> + </head> + <body></body> +</html> diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index e342632e75fb875fb217b9d3a30cd8a6ce9e2616..882db1a703717a4bebf9848c7f1d91dc2e31d26d 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -32,8 +32,7 @@ class tst_QWebEngineScript: public QObject { private Q_SLOTS: void domEditing(); - void injectionPoint(); - void injectionPoint_data(); + void loadEvents(); void scriptWorld(); void scriptModifications(); void webChannel_data(); @@ -75,44 +74,110 @@ void tst_QWebEngineScript::domEditing() QCOMPARE(evaluateJavaScriptSync(&page, "document.elementFromPoint(2, 2).id"), QVariant::fromValue(QStringLiteral("banner"))); } -void tst_QWebEngineScript::injectionPoint() +void tst_QWebEngineScript::loadEvents() { - QFETCH(int, injectionPoint); - QFETCH(QString, testScript); - - QWebEngineScript s; - s.setSourceCode("var foo = \"foobar\";"); - s.setInjectionPoint(static_cast<QWebEngineScript::InjectionPoint>(injectionPoint)); - s.setWorldId(QWebEngineScript::MainWorld); - QWebEnginePage page; - 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()); - const QVariant expected(QVariant::fromValue(QStringLiteral("SUCCESS"))); - QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.myContents"), expected); -} - -void tst_QWebEngineScript::injectionPoint_data() -{ - QTest::addColumn<int>("injectionPoint"); - QTest::addColumn<QString>("testScript"); - QTest::newRow("DocumentCreation") << static_cast<int>(QWebEngineScript::DocumentCreation) - << 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() {\ - 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);\ - } \ - };"); + // Test relative order of injection and loading. + // + // - install event listeners for "DOMContentLoaded" and "load" events + // - install user scripts for every injection point + // - check that event listeners and user scripts execute in the expected order + + class Page; + class Profile : public QWebEngineProfile { + QWebEngineScript scriptFor(QWebEngineScript::ScriptWorldId worldId, + QWebEngineScript::InjectionPoint injectionPoint) { + QWebEngineScript script; + script.setWorldId(worldId); + script.setInjectionPoint(injectionPoint); + script.setRunsOnSubFrames(true); + if (injectionPoint == QWebEngineScript::DocumentCreation) { + script.setSourceCode(QStringLiteral(R"( + var log = ["DocumentCreation"]; + for (let type of ["DOMContentLoaded", "load"]) { + window.addEventListener(type, () => log.push(type)); + } + )")); + } else if (injectionPoint == QWebEngineScript::DocumentReady) { + script.setSourceCode(QStringLiteral(R"(log.push("DocumentReady"))")); + } else { + script.setSourceCode(QStringLiteral(R"(log.push("Deferred"))")); + } + return script; + } + public: + Profile() { + scripts()->insert(scriptFor(QWebEngineScript::MainWorld, QWebEngineScript::DocumentCreation)); + scripts()->insert(scriptFor(QWebEngineScript::MainWorld, QWebEngineScript::DocumentReady)); + scripts()->insert(scriptFor(QWebEngineScript::MainWorld, QWebEngineScript::Deferred)); + scripts()->insert(scriptFor(QWebEngineScript::ApplicationWorld, QWebEngineScript::DocumentCreation)); + scripts()->insert(scriptFor(QWebEngineScript::ApplicationWorld, QWebEngineScript::DocumentReady)); + scripts()->insert(scriptFor(QWebEngineScript::ApplicationWorld, QWebEngineScript::Deferred)); + } + std::list<Page> pages; + }; + + class Page : public QWebEnginePage { + QWebEnginePage *createWindow(WebWindowType) override { + profile.pages.emplace_back(profile); + return &profile.pages.back(); + }; + public: + Page(Profile &profile) : QWebEnginePage(&profile), profile(profile) {} + QVariant eval(const QString &code, QWebEngineScript::ScriptWorldId worldId) + { + return evaluateJavaScriptSyncInWorld(this, code, worldId); + } + Profile &profile; + QSignalSpy spy{this, &QWebEnginePage::loadFinished}; + }; + + Profile profile; + profile.pages.emplace_back(profile); + Page &page = profile.pages.back(); + + const QStringList expected = { + "DocumentCreation", + "DOMContentLoaded", + "DocumentReady", + "load", + "Deferred" + }; + + // Single frame / setHtml + page.setHtml(QStringLiteral("<!DOCTYPE html><html><head><title>mr</title></head><body></body></html>")); + QTRY_COMPARE(page.spy.count(), 1); + QCOMPARE(page.spy.takeFirst().value(0).toBool(), true); + QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + + // Multiple frames + page.load(QUrl("qrc:/resources/test_iframe_main.html")); + QTRY_COMPARE(page.spy.count(), 1); + QCOMPARE(page.spy.takeFirst().value(0).toBool(), true); + QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + QCOMPARE(page.eval("window[0].log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window[0].log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + QCOMPARE(page.eval("window[0][0].log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window[0][0].log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + + // Cross-process navigation + page.load(QUrl("chrome://gpu")); + QTRY_COMPARE(page.spy.count(), 1); + QCOMPARE(page.spy.takeFirst().value(0).toBool(), true); + QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + + // Using window.open from JS + QCOMPARE(profile.pages.size(), 1u); + page.load(QUrl("qrc:/resources/test_window_open.html")); + QTRY_COMPARE(profile.pages.size(), 2u); + QTRY_COMPARE(profile.pages.front().spy.count(), 1); + QTRY_COMPARE(profile.pages.back().spy.count(), 1); + QCOMPARE(profile.pages.front().eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(profile.pages.front().eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + QCOMPARE(profile.pages.back().eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(profile.pages.back().eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); } void tst_QWebEngineScript::scriptWorld() diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc index 8b7a11cf2d2b629eff212ccad4628b70da073296..9960a37baabf281c1cc6367c1ec592f4dd299ac3 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.qrc @@ -3,5 +3,6 @@ <file>resources/test_iframe_main.html</file> <file>resources/test_iframe_outer.html</file> <file>resources/test_iframe_inner.html</file> + <file>resources/test_window_open.html</file> </qresource> </RCC>