From 931b2220986b5ef5569036080696aa6dfb9406a3 Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Tue, 5 Mar 2024 23:24:34 +0100
Subject: [PATCH] Fix require behavior for modules

---
 .../script-engine/src/v8/ScriptEngineV8.cpp   |  5 +++
 .../src/ScriptEngineNetworkedTests.cpp        | 34 ++++++++++++++++++-
 .../src/ScriptEngineNetworkedTests.h          |  1 +
 tests/script-engine/src/tests/b_require.js    |  6 ++++
 tests/script-engine/src/tests/c_require.js    |  6 ++++
 5 files changed, 51 insertions(+), 1 deletion(-)
 create mode 100644 tests/script-engine/src/tests/b_require.js
 create mode 100644 tests/script-engine/src/tests/c_require.js

diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
index d10b1c2d15..1b92fa8c56 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
@@ -664,6 +664,11 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
             }
             // "Script" API is context-dependent, so it needs to be recreated for each new context
             registerGlobalObject("Script", new ScriptManagerScriptingInterface(_manager), ScriptEngine::ScriptOwnership);
+            auto Script = globalObject().property("Script");
+            auto require = Script.property("require");
+            auto resolve = Script.property("_requireResolve");
+            require.setProperty("resolve", resolve, ScriptValue::ReadOnly | ScriptValue::Undeletable);
+            globalObject().setProperty("require", require, ScriptValue::ReadOnly | ScriptValue::Undeletable);
 
             // Script.require properties need to be copied, since that's where the Script.require cache is
             // Get source and destination Script.require objects
diff --git a/tests/script-engine/src/ScriptEngineNetworkedTests.cpp b/tests/script-engine/src/ScriptEngineNetworkedTests.cpp
index 9648e88d56..c757e009c6 100644
--- a/tests/script-engine/src/ScriptEngineNetworkedTests.cpp
+++ b/tests/script-engine/src/ScriptEngineNetworkedTests.cpp
@@ -120,7 +120,7 @@ ScriptManagerPointer ScriptEngineNetworkedTests::makeManager(const QString &scri
     return sm;
 }
 
-void ScriptEngineNetworkedTests::testRequire() {
+void ScriptEngineNetworkedTests::testScriptRequire() {
     auto sm = makeManager(
         "print(\"Starting\");"
         "Script.require('./tests/c.js');"
@@ -153,6 +153,38 @@ void ScriptEngineNetworkedTests::testRequire() {
     }
 }
 
+void ScriptEngineNetworkedTests::testRequire() {
+    auto sm = makeManager(
+        "print(\"Starting\");"
+        "require('./tests/c_require.js');"
+        "print(\"Done\");"
+        "Script.stop(true);", "testRequire.js");
+    QStringList printed;
+    QStringList expected {"Starting", "Value from A: 6", "Value from B: 6", "Done"};
+
+
+    QVERIFY(!sm->isRunning());
+    QVERIFY(!sm->isStopped());
+    QVERIFY(!sm->isFinished());
+
+    connect(sm.get(), &ScriptManager::printedMessage, [&printed](const QString& message, const QString& engineName){
+        printed.append(message);
+    });
+
+
+    qInfo() << "About to run script";
+    sm->run();
+
+    QVERIFY(!sm->isRunning());
+    QVERIFY(!sm->isStopped());
+    QVERIFY(sm->isFinished());
+
+    QVERIFY(printed.length() == expected.length());
+    for(int i=0;i<printed.length();i++) {
+        QString nomatch = QString("Result '%1' didn't match expected '%2'").arg(printed[i]).arg(expected[i]);
+        QVERIFY2(printed[i] == expected[i], qPrintable(nomatch));
+    }
+}
 
 
 void ScriptEngineNetworkedTests::testRequireInfinite() {
diff --git a/tests/script-engine/src/ScriptEngineNetworkedTests.h b/tests/script-engine/src/ScriptEngineNetworkedTests.h
index d88478f83e..f1b25440f1 100644
--- a/tests/script-engine/src/ScriptEngineNetworkedTests.h
+++ b/tests/script-engine/src/ScriptEngineNetworkedTests.h
@@ -27,6 +27,7 @@ class ScriptEngineNetworkedTests : public QObject {
 private slots:
     void initTestCase();
     void testRequire();
+    void testScriptRequire();
     void testRequireInfinite();
 
 
diff --git a/tests/script-engine/src/tests/b_require.js b/tests/script-engine/src/tests/b_require.js
new file mode 100644
index 0000000000..2022cb641c
--- /dev/null
+++ b/tests/script-engine/src/tests/b_require.js
@@ -0,0 +1,6 @@
+
+// b.js
+var a = require('./a.js');
+a.value += 1;
+console.log('message from b');
+module.exports = a.value;
\ No newline at end of file
diff --git a/tests/script-engine/src/tests/c_require.js b/tests/script-engine/src/tests/c_require.js
new file mode 100644
index 0000000000..ea7b005b53
--- /dev/null
+++ b/tests/script-engine/src/tests/c_require.js
@@ -0,0 +1,6 @@
+
+// c.js
+var a = require('./a.js');
+var b = require('./b_require.js');
+print("Value from A: " + a.value);
+print("Value from B: " + b);
\ No newline at end of file