selenium-webdriver将一个函数数组作为参数传递给executeScript

时间:2016-04-06 02:10:43

标签: javascript selenium-webdriver webdriverjs

import webdriver from 'selenium-webdriver';

const driver = new webdriver.Builder()
              .withCapabilities(webdriver.Capabilities.chrome())
              .build();

driver.get('https://www.google.com');
let foo = function(rules) {
  rules.forEach(rule => {
    rule();
  });
}
let bar = function() { return 'bar' };
let baz = function() { return 'baz' };
driver.executeScript(foo, [bar, baz]).then(function(result) {
  console.log(result);
});

driver.quit();

错误
WebDriverError: unknown error: rule is not a function


let foo = function(rules) {
  return rules;
  // rules.forEach(rule => {
  //   rule();
  // });
}
let bar = function() { return 'bar' };
let baz = function() { return 'baz' };
driver.executeScript(foo, [bar, baz]).then(function(result) {
  console.log(result); // refer the log pasted below
});

看起来该函数正在序列化为string

[ 'function bar() {\n  return \'bar\';\n}',
  'function baz() {\n  return \'baz\';\n}' ]

任何关于如何传递array of functions as arguments的指针都会有所帮助。

3 个答案:

答案 0 :(得分:2)

我发现了一个不同的工作,没有使用eval 显式,但是以类似的方式。

  1. 要注入的功能必须为named function
  2. function.toString()作为<script>

    的内容
    function foo(rules) {
      var result = [];
      rules.forEach(rule => {
        result.push(rule());
      });
      return result;
    }
    function bar() { return 'bar' };
    function baz() { return 'baz' };
    
    function inject(content) {
      var script = document.createElement('script');
      script.innerHTML = content;
      document.head.appendChild(script);
    }
    let script = `${bar.toString()} ${baz.toString()} ${foo.toString()}`;
    
    driver.executeScript(inject, script);
    
  3. 然后执行所需的功能

    driver.executeScript('return foo([bar, baz])').then(function(result) {
      // use the result
    });
    
  4. 完整的例子

    // example.js
    import webdriver from 'selenium-webdriver';
    
    const driver = new webdriver.Builder()
      .withCapabilities(webdriver.Capabilities.chrome())
      .build();
    
    driver.get('https://www.google.com');
    
    function foo(rules) {
      var result = [];
      rules.forEach(rule => {
        result.push(rule());
      });
      return result;
    }
    function bar() { return 'bar' };
    function baz() { return 'baz' };
    
    function inject(content) {
      var script = document.createElement('script');
      script.innerHTML = content;
      document.head.appendChild(script);
    }
    let script = `${bar.toString()} ${baz.toString()} ${foo.toString()}`;
    
    driver.executeScript(inject, script);
    
    driver.executeScript('return foo([bar, baz])').then(function(result) {
      console.log(result);
    });
    
    driver.quit();
    
    > babel-node example.js
    
    [ 'bar', 'baz' ]
    

答案 1 :(得分:0)

<强>问题: 作为函数参数传递的所有非平凡数据都将转换为字符串,因为它是从selenium驱动程序向浏览器注入内容的唯一方法。

  

参数必须是数字,布尔值,字符串,WebElement或上述任意组合的列表。

<强>解决方案 您可以将字符串转换为函数并使用eval或函数构造函数new Function('...function body here...')执行它。是的,这是非常糟糕的,但实际上,没有其他方法可以将非平凡的数据从驱动程序传递到浏览器。实际上,当您调用此driver.executeScript(foo, [], ...)时,foo函数也会转换为字符串,并使用eval在浏览器中执行。

如果我是你,我会尝试找到另一种方法来实现结果而不将函数作为参数传递。

您可以在以下网址了解详情:https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/JavascriptExecutor.html

答案 2 :(得分:0)

我认为你可以使用eval。请参阅以下代码:

driver.get('https://www.google.com');
let foo = function(rules) {
    var results = [];
    rules.forEach(rule => {
        results.push(eval(rule));
    });
    return results;
}

let bar = "(function() { return ' message returned from bar' })()";
let baz = "(function() { return 'message returned from baz' })()";

driver.executeScript(foo, [bar, baz]).then(function(result) {
    console.log(result);
});