selenium初探

这一周导师让我研究selenium。selenium支持很多语言,而我使用的是js来测试。需要安装selenium-webdriver: ^3.5.

##基础篇
我参考了很多文章,这里列下其中一下:
1、
http://jeremy-xu.oschina.io/2016/05/22/web%E7%95%8C%E9%9D%A2%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B7%B5%E4%B9%8BSelenium-WebDriver/
这篇文章详细列出了webdriver的api,包括定位UI元素对UI元素的操作在窗口或Frame间移动操作Alert窗口操作浏览器的导航及地址栏操作Cookie操作窗口高级用户接口操作等待until的用法…只能说是干货多多。给我带来了不少便利。

2、
https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
这里是官网api的介绍。详细介绍了selenium-webdriver的一些操作。但是没有until相关操作。很多不确定的东西来这里看一看都可以找到答案。

3、
http://www.cnblogs.com/fnng/p/5854875.html
虫师教你如何入门。虫师对测试方面有很深入的了解并写了Selenium 2自动化测试实战 基于pyton语言一书。不过似乎也有java版本的。

这些入门是非常非常快的。上面写的太好了,我也就不重复了。

##进阶篇
这里主要讲讲我我遇到的错误。

###Element is not clickable at point (411, 675). Other element would receive the click
元素不可点击错误。这种情况可能有原因有:

####元素不可见。比如不在可见的视图之内。关于元素可见性,请见https://www.w3.org/TR/webdriver/#element-displayedness

这个的解决有两种。
①通过action

driver.actions().mouseMove(ele).click().perform(); //记得加上perform()

②通过js

driver.executeScript("scroll(x,y)"); //x,y是坐标

或者

driver.executeScript("arguments[0].scrollIntoView()", webElement);

第一个参数也可以是函数:

driver.executeScript(() => {
  domElement.scrollIntoView();    
})

####页面正在刷新,所以无法点击元素。这种情况下可以等页面加载完成。

driver.wait(function() {
  driver.executeScript(() => {
    return document.readyState;
  })
  .then(state => {
    driver.isOk = (state === "complete");
  })
  return driver.isOk;
})

或者使用driver.sleep(ms)。不过这种机械式的等待我并不喜欢。

####该元素被其他元素挡住了。这种情况下需要等到你的目标元素可见。

driver.wait(until.elementIsVisible(webElement))

在这种情况下通过脚本执行点击也是可以的。

NoSuchElementError: no such element: Unable to locate element:

可能的原因有:

####选择器使用错误。使用By.xpath容易犯错。
####不在一个frame,这是经常遇到的错误。
比如你的某个页面加载了一个iframe。而你要定位iframe中的元素。这时候就会报这个错误。所以需要定位到这个iframe。

driver.switchTo().frame(id);
driver.findElement(...);

然后又要重定位主页面的元素,需要再次切换回到主页面。

driver.switchTo().defaultContent();

####不在一个window中,这时候需要切换window。切换window不像切换iframe那么简单。需要拿到window的句柄。

driver.getAllWindowHandles(); // 获取所有window的句柄,返回一个数组
driver.getWindowHandle(); // 获取当前window的句柄

然后遍历所有的window的数组,通过driver.getText()driver.getCurrentUrl()等来判断是不是你所需要的window。然后:

driver.switchTo().window(string)

####这一种原因更常见,比如一个异步请求,请求完成时某个元素才会在页面显示,但是代码执行的速度非常非常快,执行到这里的时候元素还没出现。
可以将driver.waitdriver.findElement结合来解决。代码如下:

driver.wait(() => {
  $_(By.css('.group-member-list .search-result-student-item')).then(() => {
	driver.isOk = true;
  }, () => {
	driver.isOk = false;
  })
  return driver.isOk;
})
delete driver.isOk;

StaleElementReferenceError: stale element reference: element is not attached to the page document

这个问题是一个非常烦的问题。我曾为它花了两天时间。为此我也找过很多资料。http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp这里是官方给出的原因。

####元素被删除了
1.页面部分刷新(ajax)或者导航到另一个页。
2.页面上的元素被js框架替换成了一个一模一样的元素。这样的话元素就是stale的。虽然页面上观察不到任何变化。实际上,我一直怀疑我的是这种原因,页面使用了react,我怀疑当我作出某处操作的时候,页面重新渲染了。后来的元素和之前的元素一模一样,但是我已经丢失了之前元素的绑定。

####元素不再绑定到dom
比如有一个tab,我们在tab上做切换操作的时候,实际上我们切换的是dom。这时候,之前dom上的元素我们不再使用(页面上不再使用),变成stale的了。

除了这些之外,我搜索其他资料的时候也发现一些原因:

####元素被重定位到页面其他位置
####元素通过ajax重新渲染到页面
####做过渡效果的时候,比如有一个div,想要让一个新的div来代替它。这时候clone老的div,让它移出去,而新的div移进来(这块我也不是很理解,文末有相关链接)

为了解决(尽可能解决)这种错误,可能的解决方法有:

####每次重新定位元素而不是存储对元素的引用

每次使用 driver.findElement() 来查找元素而不是:

let ele = driver.findElement()
......
ele.xxx
因为ele可能会丢失绑定

####利用js库的钩子
比如jquery中,动画有一个队列。可以查询一个元素上是否有动画。如果元素处于动画中,可能会报这个错误。

伪代码
driver.wait(() => {
  return animationQueue === 0
})

####等一个元素变成stale
如果知道一个元素会变成stale,那么就等它变成stale再去操作它。until中有一个方法。

driver.wati(until.stalenessOf(ele));

源码如下:

exports.stalenessOf = function stalenessOf(element) {
  return new Condition('element to become stale', function() {
    return element.getTagName().then(
        function() { return false; },
        function(e) {
          if (e instanceof error.StaleElementReferenceError) {
            return true;
          }
          throw e;
        });
  });
};

####js中设置window下的变量

$.ajax(url)
.then()
.always(() => {
  window.__ISCOMPLETED__ = true;
}) 

然后在selenium中:

driver.wait(() => {
  dirver.executeScript(() => {
    driver.isOk = (window.__ISCOMPLETED__ = true);
  })
  return driver.isOk;
})

####将操作移到js而不是使用selenium的操作

driver.executeScript(() => {
  documnet.querySelector(selector).click();
})

我就是使用这种方法的。

另外需要说明一下,永远不要使用try/catch。我不敢说selenium中所有操作是异步的。但是try/catch无法捕捉错误。你需要使用:

driver.xxxxxx
.then()
.catch()

##番外篇
来自:
http://huziketang.com/blog/posts/detail?postId=58d50da37413fc2e8240855c

想说点关于使用 await 的一些话

你在可能网络上其他地方看到一些例子,它们并没有使用 async/await,或者是使用了promise。实际上这样的代码是同步的。那么为什么也能 work 的很好呢?坦白地说,我也不知道,看起来像是在 webdriver 中有些trick 的处理。正如 selenium 文档中说道,在 Node 支持 async/await 之前,这是一个临时的解决方案。

Selenium 文档是 Java 语言。它还不完整,但是包含的信息也足够了,你做几次测试就能掌握这个技能。

来自:
http://engineeringquality.blogspot.hk/2013/08/ways-of-dealing-with.html

Is that in reality, the selection and the click action will actually be sent as 2 separate calls when it goes over the wire on Selenium’s JSON wire protocol. Doing this all in JavaScript will ensure the call gets executed in the same frame.

就是说我们使用:

driver.findElement().click()

的时候,selenium会分成两步处理。这是由于JSON wire protocol规定的。

##参考
https://stackoverflow.com/questions/11908249/debugging-element-is-not-clickable-at-point-error

http://engineeringquality.blogspot.hk/2013/08/ways-of-dealing-with.html

http://huziketang.com/blog/posts/detail?postId=58d50da37413fc2e8240855c

http://jeremy-xu.oschina.io/2016/05/22/web%E7%95%8C%E9%9D%A2%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B7%B5%E4%B9%8BSelenium-WebDriver/

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值