Watir wait_until_present超时而不是返回false

时间:2015-03-09 18:23:15

标签: ruby testing watir watir-webdriver

我还是刚开始使用Watir进行测试,但我一直在阅读关于waiting with Watir的所有地方,我无法找到解决问题的方法。

基本上我希望wait_while_presentwait_until_present在页面加载时工作。当我意识到两者都超时时,我尝试使用element.present?编写我自己的janky版本,但这也超时了。我认为这可能是当前版本的watir-webdriver的一个问题。

以下是一个给我带来很多麻烦的测试示例:

def test_rows_per_page()
  begin
    browser.element(:id => 'moar-rows').when_present.click
    browser.element(:id => 'loading').wait_while_present
    assert_text = browser.element(:id => 'num-rows').text

    browser.element(:id => 'less-rows').when_present.click
    browser.element(:id => 'loading').wait_while_present
    diff_text = browser.element(:id => 'num-rows').text

    if !(assert_text.eql? diff_text)
      screen_capture()
      assert_passed()
    else
      screen_capture()
      assert_failed()
    end
  rescue
    screen_capture()
    increment_failed() #this is how I know it's timing out
  end
end

我尝试过测试puts load_element.present?(timeout=1),它只是失败得更快。因此,wait_until_present在元素不存在时不返回false。 如何让它返回false?

我可能会尝试这个,这是对我在开始时链接的问题的回应,但我不确定它是否能解决我的问题:

Timeout::timeout(input_timeout=1) do
  #Default webdriver command here
end
rescue Timeout::Error
  raise TimeoutError
end

所以不会让我发布超过两个链接,我的声誉可怜,但watir-webdriver的源代码在GitHub上。


我忘了把特定的背景显示出来的时间:

def test_rows_per_page()
  begin
    browser.element(:id => 'moar-rows').when_present.click
    loading_element = element(:id => 'loading')
    #loading_element.wait_while_present
    assert_text = browser.element(:id => 'num-rows').text

    browser.element(:id => 'less-rows').when_present.click
    #loading_element.wait_while_present
    puts loading_element.present? #=> true
    sleep 1
    puts loading_element.present? #times out here
    sleep 1
    puts loading_element.present? 

    diff_text = browser.element(:id => 'num-rows').text
    if !(assert_text.eql? diff_text)
      screen_capture()
      assert_passed()
    else
      screen_capture()
      assert_failed()
    end
  rescue
    screen_capture()
    increment_failed() #this is how I know it's timing out
  end
end

注释掉rescue块,这是错误:

:in `eval': unknown error: Element is not clickable at point (550, 565). Other element would receive the click: <div id="loading-screen" class="loading-page-backdrop ng-scope" ng-if="pageLoading || gridLoading"></div>
(Selenium::WebDriver::Error::UnknownError)
(Session info: chrome=41.0.2272.76)
(Driver info: chromedriver=2.6.232908,platform=Mac OS X 10.10.2 x86_64)
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/response.rb:15:in `initialize'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/http/common.rb:59:in `new'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/http/common.rb:59:in `create_response'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/http/default.rb:66:in `request'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/http/common.rb:40:in `call'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/bridge.rb:640:in `raw_execute'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/bridge.rb:618:in `execute'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/remote/bridge.rb:375:in `clickElement'
from /Library/Ruby/Gems/2.0.0/gems/selenium-webdriver-2.44.0/lib/selenium/webdriver/common/element.rb:54:in `click'
from /Library/Ruby/Gems/2.0.0/gems/watir-webdriver-0.6.11/lib/watir-webdriver/elements/element.rb:132:in `click'
from /Library/Ruby/Gems/2.0.0/gems/watir-webdriver-0.6.11/lib/watir-webdriver/wait.rb:122:in `method_missing'
from /file.rb:208:in `rowsPerPage_next'

我要尝试browser.div(:id => 'loading-screen').wait_while_present看看是否有效。很难从加载页面HTML中提取idclass,因为它只在加载时才存在。 (我向开发人员询问了标识符,但我不喜欢过多地欺骗她。)


更多说明:

我的主要问题是如果元素不存在,wait_while_present似乎不会继续。这就是我尝试使用present?编写自己的janky版本的原因,但是当元素不存在时,它也会超时而不是返回false。我更愿意让Watir版本正常运行。

对于加载div,我已尝试使用idclass两种方式,并且当div不存在时,它仍然会超时而不是继续。

我目前有这些全局等待设置,如果这完全相关:

browser.driver.manage.timeouts.implicit_wait = 30
browser.driver.manage.timeouts.page_load = 30
Watir.default_timeout = 30
如果元素既存在又可见,那么

present?应该返回true,所以如果加载div不可见,那么它应该只返回false,对吧?即使它存在但隐藏了吗?我真的试着自己解决这个问题。

请告诉我,我疯了,有一些简单的方法可以解决这个问题,比如重新安装Ruby或其他东西。

3 个答案:

答案 0 :(得分:2)

看起来你完全误解了等待功能的目的。我这样说是因为你说了

  

我的主要问题是wait_while_present似乎没有继续   元素不存在。

行为是设计

虽然`.present?&#39;方法返回true或false(这是你用ruby编写的以问号结尾的任何方法所期望的),而不是各种各样的等待&#39;功能工作。也不合理地假设他们确实返回了真或假,因为他们的方法名称不以问号结尾。

这些等待函数的目的是等待指定的持续时间达到 的预期条件(相反)如果超时到期而没有满足条件,则继续,或者提出错误。你可以:

  • 等待元素存在
  • 等待元素出现
  • 等待条件成为现实
  • 等到条件变为错误

使用这些方法进行同步时的假设是:如果超出超时,则脚本无法可靠地继续。因此,测试在那时失败了。

这种提高错误(又称异常)以使测试失败的业务几乎是所有语言中所有常见测试框架的标准行为..黄瓜,rspec,junit,minitest,nunit等测试断言/期望的工作原理相同方式,如果被断言的东西失败,则会引发错误。框架&#39;捕获&#39;错误,将详细信息记录为测试结果的一部分,使测试/方案失败并转移到下一个测试/方案。如果在测试期间执行的任何方法失败,例如尝试单击不存在的按钮,则会引发错误并且测试失败。

对于您想要做的事情,要使用这些方法,您需要将等待调用包装在异常处理代码中以“救援”#39;错误,如果方法最终引发错误或编写自己的方法在等待一段时间的情况下等待可能显示的条件,然后根据情况有条件地响应结果,而不仅仅是提出错误。

当没有简单的方法来了解客户端代码是否忙于更新页面,等待响应时,处理具有大量动态客户端呈现以响应用户操作的网页可能非常棘手服务电话,或等待用户输入。没有惯例,没有标准的方法来判断是哪种情况。如果你很幸运,或者你的程序员关心测试能力,那么他们可能会帮你找出可以用来确定情况的东西。例如,许多站点都有一个微调器图标,只要客户端代码忙于更新页面或从服务器获取数据,它们就会显示,然后您可以使用该元素的可见性来了解代码何时需要等待或何时可以安全地继续

请记住,这些方法可以使用参数来设置超时,并且在某些情况下会显示错误消息。利用它可以大大提高您排除故障的能力..

例如,如果你有一个非常可靠的微调器,你可以做这样的事情,等待它出现最多三秒钟,然后最多10秒让它消失

b.element(:id => 'loading').wait_until_present(timeout=3)
b.element(:id => 'loading').wait_while_present(timeout=10)

如果我们希望如果旋转器永远不会出现而不会失败,只是继续前进,但如果它超过10秒就会失败,那么你可以像这样做一些基本的exception handling

begin
  b.element(:id => 'loading').wait_until_present(timeout=3)
rescue
  puts "waited three seconds without seeing spinner"
end
b.element(:id => 'loading').wait_while_present(timeout=10)

如果无法访问您正在测试的页面,其他任何人都很难就如何使您的代码以稳健的方式与页面同步而提出具体建议。

答案 1 :(得分:0)

我想我会放弃并留下sleep s。

(在我的帖子中忽略classid名称中的随机更改。还snake_casecamelCase。我没有这样写相信我成功地找到了有问题的HTML元素。)

unknown error: Element is not clickable at point (550, 565). 
Other element would receive the click: <div id="dashboard-loading-screen" class="loading-page-backdrop ng-scope" 
ng-if="pageLoading || gridLoading"></div> (Selenium::WebDriver::Error::UnknownError) (Session info: chrome=41.0.2272.76)

这是整个测试的消毒版,让我发疯。我在调试模式下没有加载问题,因为当我调试它时有足够的时间加载,所以我不得不扔掉一堆put来弄清楚是什么它失败了。

另请注意,我没有编写此测试的原始版本,我只是想让它正确断言。

def dashboard_rowsPerPage_next(targetRows)
  begin
    dashboard_rowsPerPage_internal(targetRows) #click drop-down to choose num of rows/page
    browser.scroll.to :bottom
    beforeRowsText = $browser.div(:class => 'grid-rows-of-label').when_present.text.split(" ", 4).last #page 1

    #I put this instead of wait_while_present
    if (puts browser.html.include?("loading-page-backdrop ng-scope"))
      Watir::Wait.while { browser.html.include? "loading-page-backdrop ng-scope"}
    end
    puts 'a'
    puts browser.html.include?("loading-page-backdrop ng-scope")
    puts browser.html.include?("loading-page-backdrop ng-scope")

    #here's where I get the error message
    browser.span(:class, "k-icon k-i-arrow-e").when_present.click 
    puts 'b'
    puts browser.html.include?("loading-page-backdrop ng-scope")

    if (puts browser.html.include?("loading-page-backdrop ng-scope"))
      Watir::Wait.while { browser.html.include? "loading-page-backdrop ng-scope"}
    end

    puts browser.html.include?("loading-page-backdrop ng-scope")
    puts 'c'
    puts browser.html.include?("loading-page-backdrop ng-scope")
    browser.scroll.to :bottom
    puts browser.html.include?("loading-page-backdrop ng-scope")
    afterRowsText = browser.div(:class => 'grid-rows-of-label').when_present.text.split(" ", 4).last #page 2
    puts 'd'
    Watir::Wait.while { browser.html.include? "dashboard-loading-screen"}

    if (!(beforeRowsText.eql? afterRowsText)) #page 2 text should not be the same as page 1 text
      screenCapture()
      assertPassed()
    else
      screenCapture()
      assertFailed()
    end
#  rescue
#    screenCapture()
#    increment_failed()
  end
end

所以我的输出是:(为了清晰起见,添加了注释)

true #should wait while loading image is visible before puts 'a'
a
true #this means the loading page is still visible, while isn't working
true
unknown error: Element is not clickable at point (550, 565). 
Other element would receive the click: <div id="dashboard-loading-screen" class="loading-page-backdrop ng-scope" 
ng-if="pageLoading || gridLoading"></div> (Selenium::WebDriver::Error::UnknownError) (Session info: chrome=41.0.2272.76)

我检查了beforeRowsText和afterRowsText的值,并且正确获取了这些值。

所以我会这样做,因为我很虚弱:

def dashboard_rowsPerPage_next(targetRows)
  begin
    dashboard_rowsPerPage_internal(targetRows) #click drop-down to choose num of rows/page
    browser.scroll.to :bottom
    beforeRowsText = $browser.div(:class => 'grid-rows-of-label').when_present.text.split(" ", 4).last #page 1
    sleep 10
    browser.span(:class, "k-icon k-i-arrow-e").when_present.click 
    sleep 10
    browser.scroll.to :bottom
    afterRowsText = browser.div(:class => 'grid-rows-of-label').when_present.text.split(" ", 4).last #page 2

    if (!(beforeRowsText.eql? afterRowsText)) #page 2 text should not be the same as page 1 text
      screenCapture()
      assertPassed()
    else
      screenCapture()
      assertFailed()
    end
  rescue
    screenCapture()
    increment_failed()
  end
end
等等不,没关系。它每页有25行,但每页50行都会出现相同的错误。

答案 2 :(得分:0)

我正在学习ruby / watir / cucumber,而且我还想等一下,如果超时的话会给我一个False。  我想等待大约10秒钟才能弹出或不显示,然后继续代码。例如,如果弹出窗口在不到一秒的时间内出现,则使用睡眠10是一个很大的浪费。作为初学者,我发现这样做的最好方法是使用If块。我检查元素是否存在,如果不存在,我再等3秒钟。最多9秒。它解决了我的问题。

示例:我想检查是否弹出一个单词&#34; Success&#34;出现。如果是,则打印&#34;通过&#34;。如果它没有在9秒内出现,则会打印&#34;失败&#34;。

if $browser.element(:text => "Success").exists? == False
sleep 3
end

if $browser.element(:text => "Success").exists? == False
sleep 3
end

if $browser.element(:text => "Success").exists? == False
sleep 3
end

if $browser.element(:text => "Success").exists? == False
puts "Failed"
end

if $browser.element(:text => "Success").exists?
puts "Passed"
end

test continues

也许这会有所帮助!