Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/io/appium/java_client/AppiumDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@
*/
@SuppressWarnings("unchecked")
public class AppiumDriver<T extends WebElement>
extends DefaultGenericMobileDriver<T> implements ComparesImages, FindsByImage<T>, FindsByCustom<T> {
extends DefaultGenericMobileDriver<T> implements ComparesImages, FindsByImage<T>, FindsByCustom<T>,
ExecutesDriverScript {

private static final ErrorHandler errorHandler = new ErrorHandler(new ErrorCodesMobile(), true);
// frequently used command parameters
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/io/appium/java_client/ExecutesDriverScript.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client;

import io.appium.java_client.driverscripts.ScriptOptions;
import io.appium.java_client.driverscripts.ScriptValue;
import org.openqa.selenium.remote.Response;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;
import static io.appium.java_client.MobileCommand.EXECUTE_DRIVER_SCRIPT;

public interface ExecutesDriverScript extends ExecutesMethod {

/**
* Run a set of scripts in scope of the current session.
* This allows multiple web driver commands to be executed within one request
* and may significantly speed up the automation script performance in
* distributed client-server environments with high latency.
* Read http://appium.io/docs/en/commands/session/execute-driver for more details.
*
* @since Appium 1.14
* @param script the web driver script to execute (it should
* be a valid webdriverio code snippet by default
* unless another option is provided)
* @param options additional scripting options
* @return The script result
* @throws org.openqa.selenium.WebDriverException if there was a failure while executing the script
*/
default ScriptValue executeDriverScript(String script, @Nullable ScriptOptions options) {
Map<String, Object> data = new HashMap<>();
data.put("script", checkNotNull(script));
if (options != null) {
data.putAll(options.build());
}
Response response = execute(EXECUTE_DRIVER_SCRIPT, data);
//noinspection unchecked
Map<String, Object> value = (Map<String, Object>) response.getValue();
//noinspection unchecked
return new ScriptValue(value.get("result"), (Map<String, Object>) value.get("logs"));
}

/**
* Run a set of scripts in scope of the current session with default options.
*
* @since Appium 1.14
* @param script the web driver script to execute (it should
* be a valid webdriverio code snippet)
* @return The script result
*/
default ScriptValue executeDriverScript(String script) {
return executeDriverScript(script, null);
}
}
3 changes: 3 additions & 0 deletions src/main/java/io/appium/java_client/MobileCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public class MobileCommand {
protected static final String TOGGLE_AIRPLANE_MODE;
protected static final String TOGGLE_DATA;
protected static final String COMPARE_IMAGES;
protected static final String EXECUTE_DRIVER_SCRIPT;

public static final Map<String, CommandInfo> commandRepository;

Expand Down Expand Up @@ -184,6 +185,7 @@ public class MobileCommand {
TOGGLE_AIRPLANE_MODE = "toggleFlightMode";
TOGGLE_DATA = "toggleData";
COMPARE_IMAGES = "compareImages";
EXECUTE_DRIVER_SCRIPT = "executeDriverScript";

commandRepository = new HashMap<>();
commandRepository.put(RESET, postC("/session/:sessionId/appium/app/reset"));
Expand Down Expand Up @@ -268,6 +270,7 @@ public class MobileCommand {
commandRepository.put(TOGGLE_AIRPLANE_MODE, postC("/session/:sessionId/appium/device/toggle_airplane_mode"));
commandRepository.put(TOGGLE_DATA, postC("/session/:sessionId/appium/device/toggle_data"));
commandRepository.put(COMPARE_IMAGES, postC("/session/:sessionId/appium/compare_images"));
commandRepository.put(EXECUTE_DRIVER_SCRIPT, postC("/session/:sessionId/appium/execute_driver"));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.driverscripts;

import com.google.common.collect.ImmutableMap;

import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Optional.ofNullable;


public class ScriptOptions {
private ScriptType scriptType;
private Long timeoutMs;

/**
* Sets the script type.
*
* @param type the actual script type
* @return self instance for chaining
*/
public ScriptOptions withScriptType(ScriptType type) {
this.scriptType = checkNotNull(type);
return this;
}

/**
* Sets the script execution timeout.
* If this is not set then the maximum duration of the script
* is not limited (e. g. may block forever).
*
* @param timeoutMs the timeout in milliseconds
* @return self instance for chaining
*/
public ScriptOptions withTimeout(long timeoutMs) {
this.timeoutMs = timeoutMs;
return this;
}

/**
* Builds a values map for further usage in HTTP requests to Appium.
*
* @return The map containing the provided options
*/
public Map<String, Object> build() {
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
ofNullable(scriptType).map(x -> builder.put("type", x.name().toLowerCase()));
ofNullable(timeoutMs).map(x -> builder.put("timeout", x));
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.driverscripts;

public enum ScriptType {
WEBDRIVERIO
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.driverscripts;

import java.util.Map;

public class ScriptValue {
private final Object result;
private final Map<String, Object> logs;

public ScriptValue(Object result, Map<String, Object> logs) {
this.result = result;
this.logs = logs;
}

/**
* The result of ExecuteDriverScript call.
*
* @return The actual returned value depends on the script content
*/
public Object getResult() {
return result;
}

/**
* Retrieves logs mapping from ExecuteDriverScript call.
*
* @return Mapping keys are log levels, for example `warn` or
* `error` and the values are lists of strings that were printed
* by the script into the corresponding logging level
*/
public Map<String, Object> getLogs() {
return logs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.android;

import io.appium.java_client.driverscripts.ScriptOptions;
import io.appium.java_client.driverscripts.ScriptType;
import io.appium.java_client.driverscripts.ScriptValue;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

public class ExecuteDriverScriptTest extends BaseAndroidTest {

@Test
public void verifyBasicScriptExecution() {
String script = String.join("\n", Arrays.asList(
"const status = await driver.status();",
"console.warn('warning message');",
"return status;")
);
ScriptValue value = driver.executeDriverScript(script, new ScriptOptions()
.withTimeout(5000)
.withScriptType(ScriptType.WEBDRIVERIO));
//noinspection unchecked
assertNotNull(((Map<String, Object>) value.getResult()).get("build"));
//noinspection unchecked
assertThat(((List<String>)value.getLogs().get("warn")).get(0),
is(equalTo("warning message")));
}
}