同样需要开启bidi交互功能
ChromeOptions co = new ChromeOptions();
co.setCapability("webSocketUrl", true); //BiDi功能需要添加这个配置
WebDriver driver = new ChromeDriver(chromeOptions);
调用js函数并获取返回值
js测试代码如下
// test.js
async ()=>{
// 使用await 等待获取一个Promise 兑现的值
let data = await new Promise((resolve, reject)=>{
// 用setTimeout模拟一个异步操作, 例如一个网络请求
// resolve将兑现值复制给data
setTimeout(()=>resolve(JSON.stringify({"data":"123"})), 3000)
});
// 返回兑现值, 传给java的数据, 一个json字符串 {"data": "123"}
return data;
}
java 代码如下
String id = driver.getWindowHandle();
// 创建一个Script对象
Script script = new Script(id, driver);
// strCode 是 test.js文件中的代码
EvaluateResult evaluateResult = script.callFunctionInBrowsingContext(id, strCode, true,
Optional.empty(), Optional.empty(), Optional.empty());
EvaluateResult.Type resultType = evaluateResult.getResultType();
if(resultType == EvaluateResult.Type.SUCCESS){
EvaluateResultSuccess res = (EvaluateResultSuccess) evaluateResult;
// getValue返回的是一个Optional对象, 里面包着这 js返回的data数据
return res.getResult().getValue().get().toString();
}else{
EvaluateResultExceptionValue res = (EvaluateResultExceptionValue) evaluateResult;
throw new RuntimeException(res.getExceptionDetails().getText());
}
在沙盒sandbox中调用js函数
sandbox是CSP安全策略的一种方式, 类似于iframe, 会阻止一些弹出窗和可执行的插件、脚本运行。下面用一个例子直观演示下
测试js脚本如下
// testpop.js
() =>{
window.confirm("test"); // 弹出一个模态确认框
}
以下分别用sandbox方式和不用分别执行下这个脚本
用sandbox方式会抛出异常, 大家可以自行运行体会下
// 开启sandbox选项
EvaluateResult evaluateResult = script.callFunctionInBrowsingContext(id, "sandbox" str, true,
Optional.empty(), Optional.empty(), Optional.empty());
// 不开启sandbox
EvaluateResult evaluateResult = script.callFunctionInBrowsingContext(id, str, true,
Optional.empty(), Optional.empty(), Optional.empty())
//开启sandbox不允许执行有弹框这种js脚本, alert除外, 所以会报异常
//不开启sandbox 可以正常执行, 并且在页面中弹出一个“确认模态框”
执行js代码
使用evaluateFunctionInBrowsingContext
执行js代码 和 callFunctionInBrowsingContext
不同的是, 这个是执行一段js代码, 不可传参数, 那个是调用某个js函数 , 可以传递参数
下面演示一段相似代码看下
// test2.js
async function test(){
let data = await new Promise((resolve, reject)=>{
setTimeout(()=>resolve(JSON.stringify({"data":"123"})), 3000)
});
return data;
}
// 这里需要调用一下, 否则上面声明的函数不会执行, java代码中也获取不到data值
test();
在java中执行上面的js代码
String id = driver.getWindowHandle();
// 创建一个Script对象
Script script = new Script(id, driver);
//执行test2.js脚本
EvaluateResult evaluateResult = script.evaluateFunctionInBrowsingContext(id, str, true,
Optional.of(ResultOwnership.ROOT));
EvaluateResult.Type resultType = evaluateResult.getResultType();
if(resultType == EvaluateResult.Type.SUCCESS){
EvaluateResultSuccess res = (EvaluateResultSuccess) evaluateResult;
// 返回js脚本中的data值
return (String)res.getResult().getValue().orElseGet(()->"");
}else{
EvaluateResultExceptionValue res = (EvaluateResultExceptionValue) evaluateResult;
throw new RuntimeException(res.getExceptionDetails().getText());
}