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>