代替Watir中click_no_wait的方法——left_click

1. 下面这个方法比click_no_wait好使, 而且click_no_wait不知道为什么总提示错误, 可能是版本的问题。

2. 利用下面这个方法时, 如果不能弹出对话框也可能是版本的问题。不过还有有办法来解决的。

具体如下: 使用下面的代码也取代 left_click中的WindowsInput.left_click。 

#M0USEEVENTF_LEFTDOWN = 2
#MOUSEEVENTF_LEFTUP = 4

@mouse_event=Win32API.new("user32","mouse_event",['L']*5,'V')
@mouse_event.Call(2,0,0,0,0)
@mouse_event.Call(4,0,0,0,0)


我在刚学watir的时候被js弹出对话框折腾的死去活来,如何处理弹出框的方法网络上一搜一大堆,但是如何点出弹出框的文章却很少。因为如果用click或者click!方法点击会阻塞脚本,不能让脚本执行下去,而click_no_wait方法又不稳定(用ruby186-27_rc2.exe安装的ruby click_no_wait方法根本就不好用),当时差点让我对watir失去了信心。

还好在watir群里(群号25656482)的一位朋友给我提供了另一个替代click_no_wait的方法。
首先建一个ruby文件(我把它命名为ClickHelper.rb),把下面代码考进去。
Ruby代码  
  1. #File Name: ClickHelper.rb  
  2. require 'watir'  
  3. require 'Win32API'  
  4. module Watir  
  5.   class Element  
  6.     def top_edge  
  7.       assert_exists  
  8.       assert_enabled  
  9.       ole_object.getBoundingClientRect.top.to_i  
  10.     end  
  11.   
  12.     def top_edge_absolute  
  13.       top_edge + page_container.document.parentWindow.screenTop.to_i  
  14.     end  
  15.   
  16.     def left_edge  
  17.       assert_exists  
  18.       assert_enabled  
  19.       ole_object.getBoundingClientRect.left.to_i  
  20.     end  
  21.   
  22.     def left_edge_absolute  
  23.       left_edge + page_container.document.parentWindow.screenLeft.to_i  
  24.     end  
  25.   
  26.     def right_click  
  27.       x = left_edge_absolute  
  28.       y = top_edge_absolute  
  29.       #puts "x: #{x}, y: #{y}"  
  30.       WindowsInput.move_mouse(x, y)  
  31.       WindowsInput.right_click  
  32.     end  
  33.   
  34.     def left_click  
  35.       x = left_edge_absolute  
  36.       y = top_edge_absolute  
  37.       #puts "x: #{x}, y: #{y}"  
  38.       # need some extra push to get the cursor in the right area  
  39.       WindowsInput.move_mouse(x + 2, y + 2)  
  40.       WindowsInput.left_click  
  41.     end  
  42.   end  
  43. end  
  44.   
  45. module WindowsInput  
  46.   # Windows API functions  
  47.   SetCursorPos = Win32API.new('user32','SetCursorPos''II''I')  
  48.   SendInput = Win32API.new('user32','SendInput''IPI''I')  
  49.   # Windows API constants  
  50.   INPUT_MOUSE = 0  
  51.   MOUSEEVENTF_LEFTDOWN = 0x0002  
  52.   MOUSEEVENTF_LEFTUP = 0x0004  
  53.   MOUSEEVENTF_RIGHTDOWN = 0x0008  
  54.   MOUSEEVENTF_RIGHTUP = 0x0010  
  55.   
  56.   module_function  
  57.   
  58.   def send_input(inputs)  
  59.     n = inputs.size  
  60.     ptr = inputs.collect {|i| i.to_s}.join # flatten arrays into single string  
  61.     SendInput.call(n, ptr, inputs[0].size)  
  62.   end  
  63.   
  64.   def create_mouse_input(mouse_flag)  
  65.     mi = Array.new(7, 0)  
  66.     mi[0] = INPUT_MOUSE  
  67.     mi[4] = mouse_flag  
  68.     mi.pack('LLLLLLL'# Pack array into a binary sequence usable to SendInput  
  69.   end  
  70.   
  71.   def move_mouse(x, y)  
  72.     SetCursorPos.call(x, y)  
  73.   end  
  74.   
  75.   def right_click  
  76.     rightdown = create_mouse_input(MOUSEEVENTF_RIGHTDOWN)  
  77.     rightup = create_mouse_input(MOUSEEVENTF_RIGHTUP)  
  78.     send_input( [rightdown, rightup] )  
  79.   end  
  80.   
  81.   def left_click  
  82.     leftdown = create_mouse_input(MOUSEEVENTF_LEFTDOWN)  
  83.     leftup = create_mouse_input(MOUSEEVENTF_LEFTUP)  
  84.     send_input( [leftdown, leftup] )  
  85.   end  
  86. end  


这段代码是给watir添加了几个方法(主角Watir模块的left_click方法),其原理就是通过DOM计算出控件的位置,然后再利用Windows的API在那个计算好的坐标模拟一下鼠标点击(left_click是左击,right_click是右击,我好像是在说废话)。

好了我们来测试一下,先建立一个测试用的网页,html代码如下。
Html代码  
  1. <html>  
  2. <head>  
  3. <script>  
  4. function click_me()  
  5. {  
  6.     alert("乖");  
  7. }  
  8. </script>  
  9. <title>test page</title>  
  10. </head>  
  11. <body>  
  12. <input id='btnClickMe' type = 'button' value = 'Click Me!' onclick='click_me()'/>  
  13. </body>  
  14. </html>  

只有一个按钮,点击之后会弹出一个对话框。那我们现在写测试脚本。
Ruby代码  
  1. require 'watir'  
  2. require 'ClickHelper'  
  3.   
  4. ie = Watir::IE.attach(:title"test page")  
  5. ie.button(:id'btnClickMe').click  
  6. #ie.button(:id, 'btnClickMe').click!  
  7. #ie.button(:id, 'btnClickMe').click_no_wait  
  8. #ie.button(:id, 'btnClickMe').left_click  
  9. puts "Successful"  
  10. # Deal with the pop up window.  


分别使用四种方法点击button,结果:
click, click!方法都会弹出对话框,但是脚本会停止执行下面的步骤,也就是说不会输出"Successful",甚至脚本会永远卡在那里。
click_no_wait可以输出"Successful",但是不会弹出对话框(这个方法与ruby,watir的版本有关,相信很多人会遇到跟我一样的问题)。
left_click可以弹出对话框,也可以输出"Successful",正是我们想要的效果。

问题貌似要解决了,但是前几天我发现了left_click的一个缺陷,那就是当按钮不在屏幕中显示时按钮就按不到了。
我把一开始的html测试页代码改了一下,增加了点文字,然后把窗口缩放一下,弄成下图的样子。

此时按钮还在页面中,但是再用left_click方法就点不到了

但是遇到问题还是要解决的。这时候我想起当我们往文本框输入的时候,页面会自动将文本框调整到浏览器的屏幕中,那么如果按钮也能自动调整进来,那么就可以继续使用left_click了。
于是我查看text_field的set的源代码。在这里插一句,在cmd中输入gem server后,在浏览器地址栏里输127.0.0.1:8808就可以直接查看你已经安装的gem包的api了,非常方便(不要用IE,IE的显示有问题)。
当我看到text_field的set方法的代码时发现他要先执行一个focus的操作。
代替Watir中click_no_wait的方法——left_click_第1张图片
于是在自己测试脚本上也加上这一句。
Ruby代码  
  1. require 'watir'  
  2. require 'ClickHelper'  
  3.   
  4. ie = Watir::IE.attach(:title"test page")  
  5. ie.button(:id'btnClickMe').focus  
  6. ie.button(:id'btnClickMe').left_click  
  7. puts "Successful"  
  8. # Deal with the pop up window.  

这下果真成功了!脚本会先把按钮调整到屏幕中,然后再点击

好了,问题已经解决了,剩下的就是优化一下,把focus封装到left_click里面,这样以后就不用自己写focus了。
观察了一下,在Element类的left_edge方法中添加一句话。
    def left_edge
      assert_exists
      assert_enabled
      ole_object.focus  # 这句话是我加的
      ole_object.getBoundingClientRect.left.to_i
    end

为了保证脚本的健壮性,必须保证每次用left_click时被操作的控件都在最前。还好watir有一个方法专门干这件事,那就是bring_to_front。
还是在left_edge里加。
    def left_edge
      assert_exists
      assert_enabled
      page_container.bring_to_front      # 这句话是我加的
      ole_object.focus                        # 这句话也是我加的
      ole_object.getBoundingClientRect.left.to_i
    end

大功告成。附修改过后的脚本,嫌麻烦的直接用吧。

转: http://piecehealth.iteye.com/blog/605019


你可能感兴趣的:(html,脚本,测试,input,Ruby,button)