diff --git a/maestro-client/src/main/java/maestro/Maestro.kt b/maestro-client/src/main/java/maestro/Maestro.kt index 595f7bd78c..846041a136 100644 --- a/maestro-client/src/main/java/maestro/Maestro.kt +++ b/maestro-client/src/main/java/maestro/Maestro.kt @@ -561,10 +561,10 @@ class Maestro( } } - fun setLocation(latitude: Double, longitude: Double) { + fun setLocation(latitude: String, longitude: String) { LOGGER.info("Setting location: ($latitude, $longitude)") - driver.setLocation(latitude, longitude) + driver.setLocation(latitude.toDouble(), longitude.toDouble()) } fun eraseText(charactersToErase: Int) { diff --git a/maestro-orchestra-models/src/main/java/maestro/orchestra/Commands.kt b/maestro-orchestra-models/src/main/java/maestro/orchestra/Commands.kt index dd8dd59939..5a1efec332 100644 --- a/maestro-orchestra-models/src/main/java/maestro/orchestra/Commands.kt +++ b/maestro-orchestra-models/src/main/java/maestro/orchestra/Commands.kt @@ -698,8 +698,8 @@ data class RunFlowCommand( } data class SetLocationCommand( - val latitude: Double, - val longitude: Double, + val latitude: String, + val longitude: String, val label: String? = null ) : Command { @@ -708,7 +708,10 @@ data class SetLocationCommand( } override fun evaluateScripts(jsEngine: JsEngine): SetLocationCommand { - return this + return copy( + latitude = latitude.evaluateScripts(jsEngine), + longitude = longitude.evaluateScripts(jsEngine), + ) } } @@ -839,17 +842,23 @@ data class TravelCommand( ) : Command { data class GeoPoint( - val latitude: Double, - val longitude: Double, + val latitude: String, + val longitude: String, ) { fun getDistanceInMeters(another: GeoPoint): Double { val earthRadius = 6371 // in kilometers - val dLat = Math.toRadians(another.latitude - latitude) - val dLon = Math.toRadians(another.longitude - longitude) + val oLat = Math.toRadians(latitude.toDouble()) + val oLon = Math.toRadians(longitude.toDouble()) + + val aLat = Math.toRadians(another.latitude.toDouble()) + val aLon = Math.toRadians(another.longitude.toDouble()) + + val dLat = Math.toRadians(aLat - oLat) + val dLon = Math.toRadians(aLon - oLon) val a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + - Math.cos(Math.toRadians(latitude)) * Math.cos(Math.toRadians(another.latitude)) * + Math.cos(Math.toRadians(oLat)) * Math.cos(Math.toRadians(aLat)) * Math.sin(dLon / 2) * Math.sin(dLon / 2) val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) @@ -865,7 +874,9 @@ data class TravelCommand( } override fun evaluateScripts(jsEngine: JsEngine): Command { - return this + return copy( + points = points.map { it.copy(latitude = it.latitude.evaluateScripts(jsEngine), longitude = it.longitude.evaluateScripts(jsEngine)) } + ) } } diff --git a/maestro-orchestra/src/main/java/maestro/orchestra/geo/Traveller.kt b/maestro-orchestra/src/main/java/maestro/orchestra/geo/Traveller.kt index a389818622..c8b74d4654 100644 --- a/maestro-orchestra/src/main/java/maestro/orchestra/geo/Traveller.kt +++ b/maestro-orchestra/src/main/java/maestro/orchestra/geo/Traveller.kt @@ -43,14 +43,20 @@ object Traveller { val timeToSleep = timeToTravelInMilliseconds / steps - val latitudeStep = (end.latitude - start.latitude) / steps - val longitudeStep = (end.longitude - start.longitude) / steps + val sLat = start.latitude.toDouble() + val sLon = start.longitude.toDouble() + + val eLat = end.latitude.toDouble() + val eLon = end.longitude.toDouble() + + val latitudeStep = (eLat - sLat) / steps + val longitudeStep = (eLon - sLon) / steps for (i in 1..steps) { - val latitude = start.latitude + (latitudeStep * i) - val longitude = start.longitude + (longitudeStep * i) + val latitude = sLat + (latitudeStep * i) + val longitude = sLon + (longitudeStep * i) - maestro.setLocation(latitude, longitude) + maestro.setLocation(latitude.toString(), longitude.toString()) Thread.sleep(timeToSleep) } } 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 1fa604d8f0..5873602fea 100644 --- a/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt +++ b/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlFluentCommand.kt @@ -319,8 +319,8 @@ data class YamlFluentCommand( val longitude = spitPoint[1].toDoubleOrNull() ?: throw SyntaxError("Invalid travel point longitude: $point") TravelCommand.GeoPoint( - latitude = latitude, - longitude = longitude, + latitude = latitude.toString(), + longitude = longitude.toString(), ) }, speedMPS = command.speed, diff --git a/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlSetLocation.kt b/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlSetLocation.kt index d80b28a8c3..b35b4413b7 100644 --- a/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlSetLocation.kt +++ b/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlSetLocation.kt @@ -3,7 +3,7 @@ package maestro.orchestra.yaml import com.fasterxml.jackson.annotation.JsonCreator data class YamlSetLocation @JsonCreator constructor( - val latitude: Double, - val longitude: Double, + val latitude: String, + val longitude: String, val label: String? = null, ) diff --git a/maestro-orchestra/src/test/java/maestro/orchestra/MaestroCommandTest.kt b/maestro-orchestra/src/test/java/maestro/orchestra/MaestroCommandTest.kt index db6a9a41f9..1d78a59350 100644 --- a/maestro-orchestra/src/test/java/maestro/orchestra/MaestroCommandTest.kt +++ b/maestro-orchestra/src/test/java/maestro/orchestra/MaestroCommandTest.kt @@ -33,7 +33,7 @@ internal class MaestroCommandTest { @Test fun `description (with a label)`() { // given - val maestroCommand = MaestroCommand(SetLocationCommand(12.5266, 78.2150, "Set Location to Test Laboratory")) + val maestroCommand = MaestroCommand(SetLocationCommand("12.5266", "78.2150", "Set Location to Test Laboratory")) // when val description = maestroCommand.description() @@ -42,4 +42,17 @@ internal class MaestroCommandTest { assertThat(description) .isEqualTo("Set Location to Test Laboratory") } + + @Test + fun `description (negative coordinates)`() { + // given + val maestroCommand = MaestroCommand(SetLocationCommand("-12.5266", "-78.2150", "Set location with negative coordinates")) + + // when + val description = maestroCommand.description() + + // then + assertThat(description) + .isEqualTo("Set location with negative coordinates") + } } 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 61f0174887..dedaa7b6ec 100644 --- a/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt +++ b/maestro-orchestra/src/test/java/maestro/orchestra/yaml/YamlCommandReaderTest.kt @@ -439,8 +439,8 @@ internal class YamlCommandReaderTest { centerElement = false ), SetLocationCommand( - latitude = 12.5266, - longitude = 78.2150, + latitude = "12.5266", + longitude = "78.2150", label = "Set Location to Test Laboratory" ), StartRecordingCommand( @@ -460,10 +460,10 @@ internal class YamlCommandReaderTest { ), TravelCommand( points = listOf( - TravelCommand.GeoPoint(0.0,0.0), - TravelCommand.GeoPoint(0.1,0.0), - TravelCommand.GeoPoint(0.1,0.1), - TravelCommand.GeoPoint(0.0,0.1), + TravelCommand.GeoPoint("0.0","0.0"), + TravelCommand.GeoPoint("0.1","0.0"), + TravelCommand.GeoPoint("0.1","0.1"), + TravelCommand.GeoPoint("0.0","0.1"), ), speedMPS = 2000.0, label = "Run around the north pole" @@ -604,4 +604,11 @@ internal class YamlCommandReaderTest { private fun commands(vararg commands: Command): List = commands.map(::MaestroCommand).toList() + + @Test + fun setLocationSyntaxError( + @YamlFile("026_setLocation_syntaxError.yaml") e: SyntaxError, + ) { + assertThat(e.message).contains("Cannot deserialize value of type") + } } diff --git a/maestro-orchestra/src/test/resources/YamlCommandReaderTest/026_setLocation_syntaxError.yaml b/maestro-orchestra/src/test/resources/YamlCommandReaderTest/026_setLocation_syntaxError.yaml new file mode 100644 index 0000000000..fd163c571e --- /dev/null +++ b/maestro-orchestra/src/test/resources/YamlCommandReaderTest/026_setLocation_syntaxError.yaml @@ -0,0 +1,5 @@ +appId: com.example.app +--- +setLocation: + latitude: 12.5266 + longitude: 78.2150 diff --git a/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt b/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt index 139ba74767..58b115c305 100644 --- a/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt +++ b/maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt @@ -743,6 +743,8 @@ class IntegrationTest { "NON_EXISTENT_TEXT" to "nonExistentText", "NON_EXISTENT_ID" to "nonExistentId", "URL" to "secretUrl", + "LAT" to "37.82778", + "LNG" to "-122.48167", ) ) @@ -770,7 +772,8 @@ class IntegrationTest { Event.Tap(Point(50, 50)), Event.Tap(Point(50, 50)), Event.InputText("\${PASSWORD} is testPassword"), - Event.OpenLink("https://example.com/secretUrl") + Event.OpenLink("https://example.com/secretUrl"), + Event.SetLocation(latitude = 37.82778, longitude = -122.48167), ) ) } diff --git a/maestro-test/src/test/resources/028_env.yaml b/maestro-test/src/test/resources/028_env.yaml index 3cb804712c..9e59e9ba76 100644 --- a/maestro-test/src/test/resources/028_env.yaml +++ b/maestro-test/src/test/resources/028_env.yaml @@ -17,4 +17,7 @@ appId: com.example.app - assertNotVisible: id: .*${NON_EXISTENT_ID}.* - inputText: \${PASSWORD} is ${PASSWORD} -- openLink: https://example.com/${URL} \ No newline at end of file +- openLink: https://example.com/${URL} +- setLocation: + latitude: ${LAT} + longitude: ${LNG}