我对Selenium很新。我设法使用下面的nodejs代码打开一个网站
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder()
.forBrowser('chrome')
.build();
console.log(driver);
driver.get('https://web.whatsapp.com');
//perform all other operations here.
https://web.whatsapp.com已打开,我手动扫描QR码并登录。现在我有不同的javascript文件来执行删除等操作,清除web.whatsapp.com内的聊天等...
现在如果我收到一些错误,我会调试,当我使用node test.js
再次运行脚本时,再加载页面需要2分钟,然后执行我需要的步骤。我只是想重新打开已打开的选项卡并继续我的脚本,而不是打开新窗口。
编辑第2天:仍在搜索解决方案。我尝试下面的代码来保存对象并重用它..这是正确的方法吗?我收到了JSON解析错误。
var o = new chrome.Options();
o.addArguments("user-data-dir=/Users/vishnu/Library/Application Support/Google/Chrome/Profile 2");
o.addArguments("disable-infobars");
o.addArguments("--no-first-run");
var driver = new webdriver.Builder().withCapabilities(webdriver.Capabilities.chrome()).setChromeOptions(o).build();
var savefile = fs.writeFile('data.json', JSON.stringify(util.inspect(driver)) , 'utf-8');
var parsedJSON = require('./data.json');
console.log(parsedJSON);
答案 0 :(得分:1)
我花了一些时间和几种不同的方法,但我设法解决了一些问题,我认为可以解决你的问题并允许以相当不错的方式开发测试。
因为它没有直接回答如何在Selenium中重复使用浏览器会话的问题(使用他们的JavaScript API),我将首先介绍我提出的解决方案,然后简要讨论其他方法我试过了。它可能会给别人一个想法并帮助他们以更好/更好的方式解决这个问题。谁知道。至少我的尝试将被记录下来。
因为我没有设法实际重用浏览器会话(见下文),我想我可以尝试别的东西。方法如下。
init.js
)并在单独的文件中进行测试(test.js
)。test.js
),检查错误,并关闭浏览器实例并停止主循环。test.js
中的测试导出主循环正在执行的测试函数。它传递一个驱动程序实例来使用。此处发生的任何错误都会被主循环捕获。因为浏览器实例只打开一次,所以我们必须只使用WhatsApp(扫描QR码)进行一次身份验证的手动过程。之后,运行测试将重新加载web.whatsapp.com,但它会记住我们已经过身份验证,因此可以立即运行我们在test.js
中定义的任何测试。
为了使主循环保持活动,我们必须捕获可能在测试中发生的每个错误。不幸的是,我不得不求助于uncaughtException
。
这是我想出的上述想法的实现。如果你想这样做,可以让这个更加漂亮。我在这里很简单(希望我能管理)。
<强> init.js 强>
这是上述想法的主要循环。
var webdriver = require('selenium-webdriver'),
by = webdriver.By,
until = webdriver.until,
driver = null,
prompt = '> ',
testPath = 'test.js',
lastError = null;
function initDriver() {
return new Promise((resolve, reject) => {
// already opened a browser? done
if (driver !== null) {
resolve();
return;
}
// open a new browser, let user scan QR code
driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('https://web.whatsapp.com');
process.stdout.write("Please scan the QR code within 30 seconds...\n");
driver.wait(until.elementLocated(by.className('chat')), 30000)
.then(() => resolve())
.catch((timeout) => {
process.stdout.write("\b\bTimed out waiting for code to" +
" be scanned.\n");
driver.quit();
reject();
});
});
}
function recordError(err) {
process.stderr.write(err.name + ': ' + err.message + "\n");
lastError = err;
// let user know that test failed
process.stdout.write("Test failed!\n");
// indicate we are ready to read the next command
process.stdout.write(prompt);
}
process.stdout.write(prompt);
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
var chunk = process.stdin.read();
if (chunk === null) {
// happens on initialization, ignore
return;
}
// do various different things for different commands
var line = chunk.trim(),
cmds = line.split(/\s+/);
switch (cmds[0]) {
case 'error':
// print last error, when applicable
if (lastError !== null) {
console.log(lastError);
}
// indicate we are ready to read the next command
process.stdout.write(prompt);
break;
case 'run':
// open a browser if we didn't yet, execute tests
initDriver().then(() => {
// carefully load test code, report SyntaxError when applicable
var file = (cmds.length === 1 ? testPath : cmds[1] + '.js');
try {
var test = require('./' + file);
} catch (err) {
recordError(err);
return;
} finally {
// force node to read the test code again when we
// require it in the future
delete require.cache[__dirname + '/' + file];
}
// carefully execute tests, report errors when applicable
test.execute(driver, by, until)
.then(() => {
// indicate we are ready to read the next command
process.stdout.write(prompt);
})
.catch(recordError);
}).catch(() => process.stdin.destroy());
break;
case 'quit':
// close browser if it was opened and stop this process
if (driver !== null) {
driver.quit();
}
process.stdin.destroy();
return;
}
});
// some errors somehow still escape all catches we have...
process.on('uncaughtException', recordError);
<强> test.js 强>
这是上述想法的考验。我写了一些东西只是为了测试主循环和一些WebDriver功能。这里几乎可以做任何事情。我已经使用promises使测试执行与主循环很好地协同工作。
var driver, by, until,
timeout = 5000;
function waitAndClickElement(selector, index = 0) {
driver.wait(until.elementLocated(by.css(selector)), timeout)
.then(() => {
driver.findElements(by.css(selector)).then((els) => {
var element = els[index];
driver.wait(until.elementIsVisible(element), timeout);
element.click();
});
});
}
exports.execute = function(d, b, u) {
// make globally accessible for ease of use
driver = d;
by = b;
until = u;
// actual test as a promise
return new Promise((resolve, reject) => {
// open site
driver.get('https://web.whatsapp.com');
// make sure it loads fine
driver.wait(until.elementLocated(by.className('chat')), timeout);
driver.wait(until.elementIsVisible(
driver.findElement(by.className('chat'))), timeout);
// open menu
waitAndClickElement('.icon.icon-menu');
// click profile link
waitAndClickElement('.menu-shortcut', 1);
// give profile time to animate
// this prevents an error from occurring when we try to click the close
// button while it is still being animated (workaround/hack!)
driver.sleep(500);
// close profile
waitAndClickElement('.btn-close-drawer');
driver.sleep(500); // same for hiding profile
// click some chat
waitAndClickElement('.chat', 3);
// let main script know we are done successfully
// we do so after all other webdriver promise have resolved by creating
// another webdriver promise and hooking into its resolve
driver.wait(until.elementLocated(by.className('chat')), timeout)
.then(() => resolve());
});
};
这是一些示例输出。 run test
的第一次调用将打开Chrome的一个实例。其他调用将使用相同的实例。发生错误时,可以如图所示进行检查。执行quit
将关闭浏览器实例并退出主循环。
$ node init.js
> run test
> run test
WebDriverError: unknown error: Element <div class="chat">...</div> is not clickable at point (163, 432). Other element would receive the click: <div dir="auto" contenteditable="false" class="input input-text">...</div>
(Session info: chrome=57.0.2987.133)
(Driver info: chromedriver=2.29.461571 (8a88bbe0775e2a23afda0ceaf2ef7ee74e822cc5),platform=Linux 4.9.0-2-amd64 x86_64)
Test failed!
> error
<prints complete stacktrace>
> run test
> quit
只需调用它们即可在其他文件中运行测试。假设您有一个文件test-foo.js
,然后在上面的提示中执行run test-foo
来运行它。所有测试都将共享相同的Chrome实例。
使用我的开发工具检查页面时,我注意到它似乎使用了localStorage
。可以export将其作为JSON,将write作为文件。在下次调用时,此文件可以是read,parsed并在重新加载页面之前写入新的浏览器实例存储。
不幸的是,WhatsApp仍然要求我扫描QR码。我试图弄清楚我错过了什么(cookies,sessionStorage
,...),但没有管理。一段时间过后,WhatsApp可能会将浏览器注册为断开连接。或者它使用其他浏览器属性(会话ID?)来识别浏览器。这是我个人的纯粹推测。
通过WebDriver启动的每个浏览器实例都有一个会话ID。可以检索此ID,因此我认为可以启动会话,然后从测试用例连接到它,然后从单独的文件运行(您可以看到这是最终解决方案的前身)。不幸的是,我无法找到设置会话ID的方法。这可能实际上是一个安全问题,我不确定。更多使用WebDriver的人可能会在这里澄清。
我确实发现可以retrieve a list of window handles并在them之间切换。不幸的是,Windows只在一个会话中共享,而不是在会话中共享。