开始的时候,一直定位不到,因为是动的。
后面发现,它在表里。然后去找关于定位表的方法。
最后才发现,是因为display:none的缘故。
然后找方法来实现
Selenium中的waitForCondition使用和编写自己的waitForElementDisplay方法
在我们在页面跳转的时候或者进行了一些操作的时候,我们需要等待某个页面或者元素的出现。对与页面的跳转我们可以用selenium.waitForPageLoad 方法,但是对于等待某个元素的出现并没有提供,只提供了一个waitForCondition 的方法。
waitForCondition方法会执行传入的js代码,直到条件成立,或者 timout时间到。
[java] view plaincopy
- selenium.waitForCondition("var value = selenium.browserbot.findElementOrNull(“id1”); value.style.display == 'none'", "10000");
waitForCondition方法中也可以有运算符的操作
[java] view plaincopy
- selenium.waitForCondition("var value = selenium.browserbot.findElementOrNull(id1); value.style.display == 'none'", || var value = selenium.browserbot.findElementOrNull(id2); value.style.display == 'none' “, "10000");
当然每次我们都去写js代码,这样会很麻烦,而且上面的代码只能判断display属性为none, 我们可以用selenium 自带的 isVisible方法来判断一个Element是否存在。 因为isVisible方法判断的跟全面,它还判断了visibility和hiden 属性。 所以我们可以创建一个更加通用的方法叫做waitForEelementDisplay 方法。 下面是代码实现:
[java] view plaincopy
- package com.safx.selenium;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.ScheduledThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- import com.safx.utility.CommonTool;
- import com.thoughtworks.selenium.SeleniumException;
- public class DriveSelenium
- {
- ScheduledThreadPoolExecutor executor = null;
- public boolean waitForElementDisplay(String locator, String time) {
- SheduleEntity entity = new SheduleEntity(CommonTool.String2Int(time));
- this.schedule(entity);
- int tempTime = 1000;
- while (!entity.isTimeout()) {
- if (selenium.isVisible(locator)) { // call selenium.isVisable method
- this.shutdownAndAwaitTermination(executor);
- return true;
- }
- Thread.sleep(tempTime);
- }
- throw new SeleniumException("ERROR: wait for '" + locator + "' " + time + "s time out!");
- }
- private void schedule(final SheduleEntity shedule) {
- executor = new ScheduledThreadPoolExecutor(1);
- executor.schedule(new Runnable() {
- @Override
- public void run() {
- shedule.setTimeout(true);
- }
- }, shedule.getTempTime(), TimeUnit.SECONDS);
- }
- private void shutdownAndAwaitTermination(ExecutorService pool) {
- pool.shutdown(); // Disable new tasks from being submitted
- try {
- // Wait a while for existing tasks to terminate
- if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
- pool.shutdownNow(); // Cancel currently executing tasks
- // Wait a while for tasks to respond to being cancelled
- if (!pool.awaitTermination(5, TimeUnit.SECONDS))
- System.err.println("Pool did not terminate");
- }
- } catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- pool.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
- }
- }
- class SheduleEntity{
- private boolean isTimeout = false;
- private int tempTime;
- public SheduleEntity( int tempTime ) {
- this.tempTime = tempTime;
- }
- public void setTimeout(boolean isTimeout) {
- this.isTimeout = isTimeout;
- }
- public boolean isTimeout() {
- return isTimeout;
- }
- public int getTempTime() {
- return tempTime;
- }
- }
- }
在上面的代码中,
1.定义一个scheduleEntiy类 用来保存,timout 延时时间 和 isTimeout 是否已经延时
2. 通过ScheduledThreadPoolExecutor 类 当定时器使用,当timeout时间到是,把ScheduleEntiy类中的isTimeout设置为True。
3. 我们定义了一个waitForElementDisplay 方法。在这个方法中做一个每隔一秒的无限循环,循环调用isVisible这个方法。如果改Element出现则返回true,如果不出现直到timeout时间到,则抛个异常出来。
源文档 <http://blog.csdn.net/caiqcong/article/details/7613028>
上周我测的产品出了新版本,上传文件这块的UI代码改动了一下。
用sendkeys这招竟然过不去,抛出了异常:
org.openqa.selenium.ElementNotVisibleException:Element is not currently visible and so may not be interacted with
就是说这个input还在,就是不可见,所以不能sendKeys了。
办法只有一个,就是用javascript把这个input给弄成可见的!
把这句document.findElementById('123').style.visibility='visible';放在selenium中执行,可是上传文件框还是没出来。我的javascript和css都比较菜,对于显示、隐藏页面元素就只会这一招。正当无奈之际,发现firebug 里html下面,input 这一行是灰的。这应该说明它是隐藏的,可是改哪儿才能管用呢?
我选中了灰的这一行,右边style里显示出了css样式display:none
百度了一下display都有什么值,有none,inline, block...,我把none改成了block,页面上出现了又大又丑的
所以:如果你想在做seleniumwebdriver 2.0自动化的时候遇到了界面里有“上传文件”的需求,input type='file' 加了样式被“美化”没了,直接sendkey不行的时候,在sendkeys之前,用javascript把它给弄出来:
JavascriptExecutor j= (JavascriptExecutor)driver;
j.executeScript("document.findElementById('123').style.display='block';");
然后再WebElement.sendKeys ("c:\abc.txt");
就OK了!这样虽然不太优雅,但也是没有办法中的办法。必竟自动化代码不能卡在这里过不去。文件上传不上去,之后的一系列验证工作都做不了。同理的还有下拉菜单中的二级菜单,有时候一闪就没,也可以把visiblility:hidden改成visible,同时设置好left和top值,让它显示出来。 就能继续了。
附上我为了解决这个问题做的网页(为了节省登录产品的时间,我单独做了一个网页来模拟这个问题)
和在firebug里观察到情况。
心里暗叫一声“惭愧”,一直嫌javascript和css麻烦,不愿意碰它们,可终归躲不过只能直面困难了。我爸帮我把多年前的javascript权威指南给带新家去了,以后没事得翻一翻。
源文档 <http://blog.sina.com.cn/s/blog_539a70d30101ajsg.html>
1、如果在样式文件或页面文件代码中直接用display:none对元素进行了隐藏,载入页面后,在没有通过js设置样式使元素显示的前提下,使用js代码会无法正确获得该元素的一些属性,比如offSetTop,offSetLeft等,返回的值会为0,通过js设置style.display来使元 素显示后才能正确获得这些值。
2、使用display:none隐藏的元素不会被百度等搜索网站检索,会影响到网站的SEO,某些情况下可以使用left:-100000px来达到同样效果。
3、 如果是通过样式文件或<style>css</style>方式来设置元素的display:none样式,用js设置style.display=""并不能使元素显示,可以使用block或inline等值来代替。通过style="display:none"直接在 元素上进行的设置不会有这个问题
4、有些情况下可以使用style.visibility来代替style.display,但是要注意的是style.visibility隐藏元素时会保留元素在页面上所占的空间,而style.display隐藏元素且让出所占页面空间。