From 90177e9b36beab921139cfb5db5a0c2fa61c36c1 Mon Sep 17 00:00:00 2001 From: Julien Ambrosio Date: Sun, 26 Jan 2025 15:16:45 -0300 Subject: [PATCH 1/2] feat: added require to load scripts using CommonJs --- .../src/main/java/maestro/js/GraalJsEngine.kt | 22 ++++++++++++++--- .../orchestra/yaml/YamlFluentCommand.kt | 4 +++- .../kotlin/maestro/test/IntegrationTest.kt | 24 +++++++++++++++++++ .../src/test/resources/121-myrequire.js | 4 ++++ .../src/test/resources/121-testrequire.js | 2 ++ .../test/resources/121_require_module.yaml | 5 ++++ 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 maestro-test/src/test/resources/121-myrequire.js create mode 100644 maestro-test/src/test/resources/121-testrequire.js create mode 100644 maestro-test/src/test/resources/121_require_module.yaml diff --git a/maestro-client/src/main/java/maestro/js/GraalJsEngine.kt b/maestro-client/src/main/java/maestro/js/GraalJsEngine.kt index 8b86422fe2..05d09577c6 100644 --- a/maestro-client/src/main/java/maestro/js/GraalJsEngine.kt +++ b/maestro-client/src/main/java/maestro/js/GraalJsEngine.kt @@ -11,6 +11,8 @@ import java.io.ByteArrayOutputStream import java.util.concurrent.TimeUnit import java.util.logging.Handler import java.util.logging.LogRecord +import java.nio.file.Paths +import java.nio.file.Path import kotlin.time.Duration.Companion.minutes private val NULL_HANDLER = object : Handler() { @@ -70,10 +72,20 @@ class GraalJsEngine( ): Value { envBinding.putAll(env) val source = Source.newBuilder("js", script, sourceName).build() - return createContext().eval(source) + val sourceDir = getSourceDirectory(sourceName) + return createContext(sourceDir).eval(source) } - private fun createContext(): Context { + private fun getSourceDirectory(sourceName: String): String { + return envBinding["MAESTRO_YAML_DIR"] ?: resolveScriptPath(sourceName).parent.toString() + } + + private fun resolveScriptPath(sourceName: String): Path { + val path = Paths.get(sourceName) + return if (path.isAbsolute) path else Paths.get(System.getProperty("user.dir"), sourceName) + } + + private fun createContext(moduleDir: String): Context { val outputStream = object : ByteArrayOutputStream() { override fun flush() { super.flush() @@ -85,6 +97,10 @@ class GraalJsEngine( val context = Context.newBuilder("js") .option("js.strict", "true") + .option("js.commonjs-require", "true") + .option("js.commonjs-require-cwd", moduleDir) + .allowExperimentalOptions(true) + .allowIO(true) .logHandler(NULL_HANDLER) .out(outputStream) .build() @@ -121,4 +137,4 @@ class GraalJsEngine( return context } -} +} \ No newline at end of file diff --git a/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt b/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt index 237138120e..a0af9e1b41 100644 --- a/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt +++ b/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt @@ -386,7 +386,9 @@ data class YamlFluentCommand( RunScriptCommand( script = resolvePath(flowPath, runScript.file) .readText(), - env = runScript.env, + env = runScript.env + mapOf( + "MAESTRO_YAML_DIR" to flowPath.parent.toString() + ), sourceDescription = runScript.file, condition = runScript.`when`?.toCondition(), label = runScript.label, diff --git a/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt b/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt index 1c7d67dc84..d5c1cbbdea 100644 --- a/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt +++ b/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt @@ -3218,6 +3218,30 @@ class IntegrationTest { ) } + @Test + fun `Case 121 - CommonJS require functionality`() { + // Given + val commands = readCommands("121_require_module") + val driver = driver { } + + val receivedLogs = mutableListOf() + + // When + Maestro(driver).use { + orchestra( + it, + onCommandMetadataUpdate = { _, metadata -> + receivedLogs += metadata.logMessages + } + ).runFlow(commands) + } + + // Then + assertThat(receivedLogs).containsExactly( + "{\"name\":\"myrequire\",\"version\":\"1.0.0\"}" + ).inOrder() + } + private fun orchestra( maestro: Maestro, ) = Orchestra( diff --git a/maestro-test/src/test/resources/121-myrequire.js b/maestro-test/src/test/resources/121-myrequire.js new file mode 100644 index 0000000000..69860e40ee --- /dev/null +++ b/maestro-test/src/test/resources/121-myrequire.js @@ -0,0 +1,4 @@ +module.exports = { + name: "myrequire", + version: "1.0.0" +}; \ No newline at end of file diff --git a/maestro-test/src/test/resources/121-testrequire.js b/maestro-test/src/test/resources/121-testrequire.js new file mode 100644 index 0000000000..7f9d4b5050 --- /dev/null +++ b/maestro-test/src/test/resources/121-testrequire.js @@ -0,0 +1,2 @@ +const myrequire = require("./121-myrequire.js"); +console.log(JSON.stringify(myrequire)); \ No newline at end of file diff --git a/maestro-test/src/test/resources/121_require_module.yaml b/maestro-test/src/test/resources/121_require_module.yaml new file mode 100644 index 0000000000..fceffcebaa --- /dev/null +++ b/maestro-test/src/test/resources/121_require_module.yaml @@ -0,0 +1,5 @@ +appId: com.other.app +jsEngine: graaljs +--- +- runScript: + file: 121-testrequire.js \ No newline at end of file From f8122e47b5bc829a5984bbbe74e6a3aac44157e6 Mon Sep 17 00:00:00 2001 From: Julien Ambrosio Date: Sun, 26 Jan 2025 15:40:27 -0300 Subject: [PATCH 2/2] test: added MAESTRO_YAML_DIR env when RunScriptCommand --- .../java/maestro/orchestra/yaml/YamlCommandReaderTest.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt b/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt index c6105fe2c9..2b4611ada1 100644 --- a/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt +++ b/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt @@ -426,7 +426,10 @@ internal class YamlCommandReaderTest { script = "const myNumber = 1 + 1;", condition = null, sourceDescription = "023_runScript_test.js", - label = "Run some special calculations" + label = "Run some special calculations", + env = mapOf( + "MAESTRO_YAML_DIR" to Paths.get("build/resources/test/YamlCommandReaderTest").toAbsolutePath().toString() + ) ), ScrollCommand( label = "Scroll down"