【问题标题】:selenium-webdriver pass an array of functions as argument to executeScriptselenium-webdriver 将函数数组作为参数传递给 executeScript
【发布时间】:2016-04-07 06:07:05
【问题描述】:
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 的指针都会有所帮助。

【问题讨论】:

标签: javascript selenium-webdriver webdriverjs


【解决方案1】:

我发现了一个不同的解决方法,不使用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
    });
    

完整示例

// 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' ]

【讨论】:

    【解决方案2】:

    问题: 所有作为参数传递给函数的重要数据都将转换为字符串,因为这是将某些东西从 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

    【讨论】:

    • 谢谢,我试过evalnew Function,没用,很可能我已经更改了实现。
    • @TimurBilalov 你说这很糟糕,我认为它是临时注入,并且只有在 WebDriver 显式注入时才会出现在测试环境中的页面上,这是一种完全有效的测试策略。
    【解决方案3】:

    我认为你可以使用 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);
    });
    

    【讨论】:

    • console.log(eval(rule)),我不想记录该函数,而是执行它。如何执行?
    • 我试过这个。 bar 和 baz 都正确执行。你能再试一次吗?
    • 对于我来说null 被打印出来,请验证发布的代码和您正在执行的代码是否相同。顺便说一句,console.log(eval(rule)); 没有返回任何值。
    • 我打算将它记录在浏览器的控制台中。如果要在 cmd 或 shell 上获取结果,则必须将每个 eval 的结果添加到列表中,然后返回。
    • @sarbbottam 我已更新代码以返回结果数组。请看一下,让我知道它是否解决了您的问题。
    猜你喜欢
    • 2012-12-07
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 2014-06-27
    • 2021-04-13
    • 1970-01-01
    • 2015-04-23
    相关资源
    最近更新 更多