是否可以在不停止节点的情况下停止selenium webdriver?
我有以下问题: 我尝试创建一个API工具,在获取get请求时执行一些Web自动化。所以我基本上在通过Express获取/启动的get请求上运行selenium webdriver。我希望该工具检查不同的元素,当它以某种方式失败时,我希望它停止selenium而不是节点实例(因为可以发送新的get请求)。
到目前为止,这是我的代码:
"use strict";
const webdriver = require('selenium-webdriver'),
Express = require('express'),
By = webdriver.By,
until = webdriver.until,
Keys = webdriver.Key,
app = new Express();
app.get("/automate", (req, res) => {
start(res);
});
function start(res) {
const driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('https://www.google.com/');
// # --- foo --- #
let errMessage = {pos: "FOO", message: "Ooops friendly robot has some troubles!"}
checkStep("#foo", errMessage);
driver.findElement(By.id("foo"))
.sendKeys("fooz");
// # --- bar --- #
errMessage = {pos: "BAR", message: "Ooops friendly robot has some troubles!"}
checkStep("#bar", errMessage);
driver.findElement(By.id("bar"))
.sendKeys("baz");
// etc…
function checkStep(selector, errMessage) {
driver.findElement(By.css(selector))
.then(() => {
console.log(`${selector} => found`);
})
.catch(err => {
console.log(`Error: ${err}`);
res.send(errMessage);
driver.quit();
});
}
}
app.get("*", (req, res) => {
res.send("Hello World");
});
// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
app.listen(port, err => {
if (err) { return console.error(err); }
console.info(`Server running on http://localhost:${port} [${env}]`);
});
到目前为止,它实际上是在工作时,当selenium找不到元素时,API的响应是正确的。在Selenium我回来了:
{
"pos": "FOO",
"message": "Ooops friendly robot has some troubles!"
}
到目前为止一切都很好。 不幸的是, BUT 停止selenium也阻止Node运行。
我得到的错误如下:
throw error;
^
WebDriverError: no such session
(Driver info: chromedriver=2.30.477690 (c53f4ad87510ee97b5c3425a14c0e79780cdf262),platform=Ma
c OS X 10.12.5 x86_64)
at WebDriverError
请帮助,谢谢!
ps:我没有使用webdriverio,因为你可以看到我使用这个包:https://www.npmjs.com/package/selenium-webdriver
答案 0 :(得分:1)
好的,我有这个工作。这是一个有点困难的解决方案,但它有效:
基本上,每次应用程序向get
收到/automate
请求时,它现在将在运行selenium脚本的节点中创建子进程(子进程有点像使用另一个线程。是一个非常好的tutorial on child processes):
"use strict";
const Express = require('express');
const { spawn } = require('child_process');
const data = require('./data.json');
const app = new Express();
app.get("/automate", (req, res) => {
const child = spawn(
process.execPath,
[`${__dirname}/test.js`, JSON.stringify(data)],
{ stdio: ['inherit', 'inherit', 'inherit', 'pipe'] }
);
child.stdio[3].on('data', data => {
const response = JSON.parse(data.toString());
res.send(response);
console.log(response);
child.kill();
});
});
app.get("*", (req, res) => {
res.send("Hello World");
});
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
app.listen(port, err => {
if (err) { return console.error(err); }
console.info(`Server running on http://localhost:${port} [${env}]`);
});
"use strict";
// hook with argument 3, that is "pipe" from parent
const Net = require('net'),
pipe = new Net.Socket({ fd: 3 });
const data = JSON.parse(process.argv[2]);
const webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until,
Keys = webdriver.Key;
function start() {
const driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('https://www.google.com/');
// # --- foo --- #
let errMessage = {pos: "lst-ib", message: "Ooops friendly robot has some troubles!"}
checkStep("#lst-ib")
.sendKeys("fooz");
driver.get('https://www.facebook.com/');
driver.get('https://www.google.com/');
driver.get('https://www.facebook.com/');
// # --- bar --- #
errMessage = {pos: "BAR", message: "Ooops friendly robot has some troubles!"}
checkStep("#bar")
.sendKeys("baz");
function checkStep(selector) {
driver.findElement(By.css(selector))
.then(() => {
console.log(`${selector} => found`);
})
.catch(err => {
console.log(`${selector} => not found`);
publish(errMessage);
driver.quit();
});
}
}
function publish(message) {
pipe.write(JSON.stringify(message));
}
start();
它的工作方式就像一个魅力:在每个请求打开一个新的子进程并杀死该子进程,如果它发送一些消息,同时还响应消息给客户端。像这样,您可以轻松地同时拥有多个selenium实例。
欢迎你。
ps:如果你讨厌所有这些来自Selenium webdriver-sync的asyncron东西似乎是一个不错的选择。它基本上将selenium代码包装为syncon而不是asyncron。就像我一样,我可以使用try {} catch {}
和driver.quit();
而不会出现任何错误。 (但这有一个缺点:它实际上阻止了你的其他nodejs代码。)