兆鹏带你读watir——【第四篇】元素定位的细节

    兆鹏再在这里说明一下,请勿以各种形式转发本篇文章,以及《兆鹏带你读watir》的所有系列文章,如果您需要转载或其他事宜,请直接联系我。《兆鹏带你读watir》之后,将继续和大家分享《兆鹏带你玩转selenium-webdriver》


联系方式:15120035568    QQ(几乎24小时在线):252413619   邮箱:robin9257#hotmail.com


上一篇我详细的和大家分享了整个定位的一个流程,但没有分享元素到底是如何定位的,定位的原理是什么,今天和大家分享元素定位的细节,即watir的核心。


本次以下面这句话为举例,来描述定位原理:

require 'rubygems'
require 'watir'

ie=Watir::IE.new
ie.goto 'image.baidu.com'
ie.text_field(:class,'kw').exist?

这段话的功能就是输出class为kw的输入框是否存在


首先我们看下textfield这个类,根据上一节,我们知道,这个类继承自InputElement,而这个类有继承自Element类

TextFiled类定义在input_element.rb文件中,它的exist?函数来自父类的父类(Element),该函数定义在element.rb中
exist?函数代码如下:

    def exists?
      begin
        locate if defined?(locate)
      rescue WIN32OLERuntimeError
        @o = nil
      end
      @o ? true: false
    end

    alias :exist? :exists?

因此,该函数执行locate函数,locate函数定义在input_element.rb中,若@o这个对象不为空,则返回true,否则返回false,而@o是在locate函数中赋值的,看下代码:
def locate
      @o = @container.locate_input_element(@how, @what, self.class::INPUT_TYPES)
    end


OK,@container是类container的实例对象,因此,我们需要看看locate_input_element函数,该函数定义在container.rb中
    def locate_input_element(how, what, types, value=nil, klass=nil)
    	puts document
      case how
      when :xpath
        return element_by_xpath(what)
      when :css
        return element_by_css(what)
      when :ole_object
        return what
      end
      # else:
      
      locator = InputElementLocator.new self, types
      locator.specifier = [how, what, value]
      # 这个document赋值很重要
      locator.document = document
      return locator.element if locator.fast_locate
      # todo: restrict search to elements.getElementsByTag('INPUT'); faster
      locator.elements = ole_inner_elements if locator.elements.nil?
      locator.klass = klass if klass 
      locator.locate
    end


代码中我进行了一下标注,其中传入的@how就是例子中的:class,watir 支持xpath定位,css定位暂时不支持。:ole_object会返回@what。当how==:class时,就会跳过case,直接到locator的实例化,并传入参数。

需要注意这句:

locator.document = document

有人可能会问,后面的这个document是什么东西,这个document是一个函数,而这个函数定义在ie-class.rb中,看下代码
    # Return the current document
    def document
      return @ie.document
    end


好,根据前几篇的知识,@ie是internetExploere.Application对象,而document就是@ie本身再带的一个属性,具体大家可以查阅:

http://msdn.microsoft.com/en-us/library/aa752052%28v=vs.85%29.aspx

接下来我们需要看看locator中的fast_locate函数,该函数返回true或false

在此之前,大家需要先了解locator中有一个变量@specifiers,他是一个hash结构,结构如下:

how => what  #how可以是:id,:class等等

:index => 1 #如果定位后,有N个元素都符合定位的要求,则只要其中的第一个元素

:value => sth #sth就是任意东西

接下来贴fast_locate代码:

    def fast_locate
      # Searching through all elements returned by ole_inner_elements
      # is *significantly* slower than IE's getElementById() and
      # getElementsByName() calls when how is :id or :name.  However
      # IE doesn't match Regexps, so first we make sure what is a String.
      # In addition, IE's getElementById() will also return an element
      # where the :name matches, so we will only return the results of
      # getElementById() if the matching element actually HAS a matching
      # :id.

      the_id = @specifiers[:id]
      puts the_id
      if the_id && the_id.class == String &&
        @specifiers[:index] == 1 && @specifiers.length == 2
        @element = @document.getElementById(the_id) rescue nil
        # Return if our fast match really HAS a matching :id
        return true if @element && @element.invoke('id') == the_id
      end

      the_name = @specifiers[:name]
      if the_name && the_name.class == String
        @elements = @document.getElementsByName(the_name) rescue nil
      end
      false
    end
  end

其中

the_id = @specifiers[:id]

这句是查询@how是不是:id,若是,则返回@what并赋值给the_id。若定位方式是用:id,且what是String类型,则可以用@doucment来定位,该变量就是InternetExploere.Application的document属性的返回,利用document.getElementById这个自带函数获取对象,将返回对象存储在@element中。后面的the_name和the_id原理一样,调用@document的getElementByName来获取对象。


总的来说,fast_locate的作用就是当定位用:id,:name时,直接用InternetExploere.Application的document属性中的getElementById和getElementByName获取。


结论:用:id 和:name 定位要比用其他方式定位快!这两种定位方式不是由watir提供的,而是有InternetExploere提供的


当没有用:id和:name定位时,用以下方法。

先介绍locator中的另一个变量:@elements这是一个数组,主要功能是保存多个html元素

locate_input_element函数,我们可以得知,若用其他方法定位,则调用ole_inner_elements函数

      locator.elements = ole_inner_elements if locator.elements.nil?
      locator.klass = klass if klass 
      locator.locate

接下来看看ole_inner_elements函数,该函数定义在container.rb中
    def ole_inner_elements
      return document.body.all
    end


他返回body中的所有元素!当页面很大时,这个会比较耗时耗内存。接下来执行locator中的locate函数,这个函数定义在locator.rb中,locate主要功能就是遍历所有元素,比较元素是否符合定位要求!

以下是代码:

def locate count = 0 puts '@klass:' puts @klass puts '@types' puts @types @elements.each do |object| if @klass == Element element = Element.new(object) else element = @klass.new(@container, @specifiers, nil) element.ole_object = object def element.locate; @o; end end catch :next_element do throw :next_element unless @types.include?(element.type) @specifiers.each do |how, what| next if how == :index unless match? element, how, what throw :next_element end end count += 1 throw :next_element unless count == @specifiers[:index] return object end end nil end

因此,我们可以得知,每个遍历的元素,第一步都是对这个HTML元素建立RUBY对象,这是一个耗时耗内存的时间!所以,为了测试方便,尽量为每个元素设置ID,个人觉得为每个元素设置ID是一件规范的事情,并不需要消耗前端开发者的时间。


因此,watir有以上两种定位方法,定位后,将元素保存在@o中,以后的操作都是对@o进行操作了。


:第三篇和第四篇我都在分享watir是如何定位元素的,其实总的来说都是在调用InternetExploere.Application中的方法,所以,大家现在应该觉得watir是一个比较简单而且比较容易理解的框架。


接下来一篇会介绍watir执行js的方法以及如何利用js作为一个接口,让ruby和html进行通信,还会介绍attach函数和鼠标键盘的使用。



I‘m Robin






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值