Селен-webdriver передать массив функций в качестве аргумента для executeScript
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 ответа
Я нашел другую работу вокруг, без использования eval
явно, но аналогичным образом.
- функции для ввода должны быть названы функцией
ввести
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);
затем выполнить нужную функцию как
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' ]
Я думаю, что вы можете использовать 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);
});
Проблема: Все нетривиальные данные, передаваемые в качестве аргументов функции, преобразуются в строку, потому что это единственный способ внедрить что-то из драйвера селена в браузер.
Аргументы должны быть числом, логическим значением, строкой, веб-элементом или списком любой комбинации вышеперечисленного.
Решение Вы можете преобразовать строку в функцию и выполнить ее, используя 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