我正在尝试通过匹配项目列表中的文本来查找并单击特定项目。与.list_of_items
匹配的元素是ul
元素,其中包含li>a
元素的列表。
我不确定如何将匹配的元素传递给下一个函数。没有id或类可用于识别元素。
driver.isElementPresent(By.css(".list_of_items")).then(function(trueFalse){
if (trueFalse){
return driver.findElements(By.css(".list_of_items a"));
}else{
console.log('err');
}
}).then(function(eleArray){
for (var i=0; i < eleArray.length; i++){
eleArray[i].getInnerHtml().then(function(html){
if (html.trim().toLowerCase() == item_to_search.toLowerCase()){
//
// how to pass the matched element to next function??
//
return true;
}
}).then(function(element){
console.log(element);
}
});
}
});
答案 0 :(得分:2)
您可以尝试使用filter
方法:
driver.isElementPresent(By.css(".list_of_items")).then(function(trueFalse){
if (trueFalse){
return driver.findElements(By.css(".list_of_items a"));
}else{
console.log('err');
throw new Error('Element not found.'); // Changed, so skips all the next steps till an error handler is found.
}
}).then(function(eleArray){
return webdriver.promise.filter(eleArray, function(element){
return element.getInnerHtml().then(function(innerText){
return innerText.trim().toLowerCase() == item_to_search.toLowerCase();
});
});
}).then(function(reducedElements){
console.log('filtered elements: ', reducedElements.length);
});
答案 1 :(得分:1)
您的代码目前正在进行不区分大小写的搜索。请注意,如果您能够让搜索区分大小写,那么您可以使用以下命令找到您的元素:
browser.findElement(By.linkText(item_to_search)).then(...);
我已经用Selenium编写了数十个应用程序测试,总是能够通过链接文本进行搜索,而不必使搜索区分大小写。 我强烈建议您组织代码以便执行此操作。
如果你不能,那么你必须扫描每个元素以找到你想要的那个。请注意,可以编写一个匹配文本的XPath表达式,即使不区分大小写,但是当你必须匹配CSS类时,我不是XPath的粉丝。所以我更喜欢一种方法,就像你一样,你扫描你的元素。 请注意,您应使用getText()
来测试元素的文本,而不是getInnerHtml()
。根据HTML测试文本值很脆弱:HTML中可能出现的内容并未改变链接文本实际所说的内容。例如,您可以<a><b>This</b> is a test</a>
文字为This is a test
,但如果您获得<a>
的内部HTML,则会获得<b>This</b> is a test
,这不是您想要匹配的内容。< / p>
这是一个实现,其中还包括我之前提到的By.linkText
方法的说明:
var webdriver = require('selenium-webdriver');
var By = webdriver.By;
var chrome = require('selenium-webdriver/chrome');
var browser = new chrome.Driver();
browser.get("http://www.example.com");
// Modify the page at example.com to add some test data.
browser.executeScript(function () {
document.body.innerHTML = '\
<ul class="list_of_items">\
<li><a>One</a></li>\
<li><a> Two </a></li>\
<li><a>Three</a></li>\
</ul>';
});
// Illustration of how to get it with By.linkText. This works if you
// are okay with having the test be case-sensitive.
browser.findElement(By.linkText("Two")).getOuterHtml().then(function (html) {
console.log("case-sensitive: " + html);
});
var item_to_search = "TwO"; // Purposely funky case, for illustration.
browser.findElements(By.css(".list_of_items a")).then(function (els){
if (els.length === 0)
// You could put tests here to determine why it is not working.
throw new Error("abort!");
// Convert it once, and only once.
var item_to_search_normalized = item_to_search.toLowerCase();
function check(i) {
if (i >= els.length)
// Element not found!
throw new Error("element not found!");
var el = els[i];
return el.getText().then(function (text) {
if (text.trim().toLowerCase() === item_to_search_normalized)
// Found the element, return it!
return el;
// Element not found yet, check the next item.
return check(i + 1);
});
}
return check(0);
}).then(function (el) {
el.getOuterHtml().then(function (html) {
console.log("case-insensitive: " + html);
});
});
browser.quit();
附加说明:
您的原始代码首先测试.list_of_items
是否存在。我没有这样做。通常,最好针对页面如您所期望的情况进行优化。你的代码是这样的,在这个页面是&#34;好&#34;你总是从至少两个操作开始(检查是否存在.list_of_items
,然后获取锚点列表)。我的实现使用一个操作。如果您想确定没有元素的原因,您可以做的是更改throw new Error("abort!")
以执行诊断。
您的原始代码在点击发生后立即结束搜索。我保持这种逻辑不变。所以我不使用webdriver.promise.filter
因为这将必然扫描列表中的每个元素。即使第一个元素是你想要的元素,也会访问所有元素。这可能非常昂贵,因为每个测试都意味着您的Selenium脚本和浏览器之间的往返。 (当一切都在同一台机器上运行时,情况就不那么糟了。当您控制远程服务器场上的浏览器时,这一点非常明显。)我使用递归来扫描列表,这也是webdriver.promise.filter
的作用,除了我在找到命中时提前返回。
这就是说,在我的代码中,我使用executeScript
将搜索范围缩小到我的Selenium脚本和浏览器之间的一次往返:
browser.executeScript(function () {
// The item_to_search value we passed is accessible as arguments[0];
var item_to_search = arguments[0].toLowerCase();
var els = document.querySelectorAll(".list_of_items a");
for (var i = 0; i < els.length; ++i) {
var el = els[i];
if (el.textContent.trim().toLowerCase() == item_to_search)
return el;
}
return null;
}, item_to_search).then(function (el) {
if (!el)
throw new Error("can't find the element!");
el.getOuterHtml().then(function (html) {
console.log("case-insensitive, using a script: " + html);
});
});
请注意executeScript
中的代码正在浏览器中执行 。这就是为什么你必须使用arguments
来获取传递给它的内容以及为什么我们必须使用.then
来获取返回值并在控制台上显示。 (如果您将console.log
放在传递给executeScript
的脚本中,它将在浏览器的控制台上显示内容。)