如何为 select 定义自定义定位策略

How to define custom locating strategy for select

我正在寻找 redefine/extend 在 Gwt 应用程序中为 select 标记定位策略的正确方法。 从 html 片段中,您可以看到 select 标签不可见。 因此,对于列表中的 select 选项,我需要单击 button 标签,而不是 select 需要下拉列表中的 li 标签。

<div class="form-group">
  <select class="bootstrap-select form-control" style="display: none; locator='gender">
    <div class="btn-group">
    <button class="dropdown-toggle" type="button" title="Male">
      <div class="dropdown-menu open">
        <ul class="dropdown-menu inner selectpicker" role="menu">
          <li data-original-index="1"> (contains a>span with option text)
            .....more options
      </ul>
    </div>
  </div>
</div>

我看到了肮脏的解决方案:在 BasePage class 中实现方法。这种方法很好 page_object sugar(options,get value, etc):

def set_nationality(country, nationality='Nationality')
  select = button_element(xpath: "//button[@title='#{nationality}']")
  select.click
  option = span_element(xpath: "//span[.='#{country}']")
  option.when_visible
  option.click
end

还有其他更清楚的方法吗?也许使用`PageObject::Widgets?

UPD:这是我期望得到的:

def bool_list(name, identifier={:index => 0}, &block)
  define_method("#{name}_btn_element") do
    platform.send('button_for', identifier.clone + "//button")
  end
  define_method("#{name}?") do
    platform.send('button_for', identifier.clone + "//button").exists?
  end
  define_method(name) do
    return platform.select_list_value_for identifier.clone + '/select' unless block_given?
    self.send("#{name}_element").value
  end
  define_method("#{name}=") do |value|
    return platform.select_list_value_set(identifier.clone + '/select', value) unless block_given?
    self.send("#{name}_element").select(value)
  end
  define_method("#{name}_options") do
    element = self.send("#{name}_element")
    (element && element.options) ? element.options.collect(&:text) : []
  end
end 

select 列表似乎具有最具识别性的属性,因此我会将其用作小部件的基本元素。所有其他元素,即按钮和列表项,都需要相对于 select 列表进行定位。在这种情况下,它们都具有相同的 div.form-group 祖先。

小部件可以定义为:

class BoolList < PageObject::Elements::SelectList
  def select(value)
    dropdown_toggle_element.click
    option = span_element(xpath: "./..//span[.='#{value}']")
    option.when_visible
    option.click
  end

  def dropdown_toggle_element
    button_element(xpath: './../div/button')
  end

  def self.accessor_methods(widget, name)
    widget.send('define_method', "#{name}_btn_element") do
      self.send("#{name}_element").dropdown_toggle_element
    end

    widget.send('define_method', "#{name}?") do
      self.send("#{name}_btn_element").exists?
    end

    widget.send('define_method', name) do
      self.send("#{name}_element").value
    end

    widget.send('define_method', "#{name}=") do |value|
      self.send("#{name}_element").select(value)
    end

    widget.send('define_method', "#{name}_options") do
      # Since the element is not displayed, we need to check the inner HTML
      element = self.send("#{name}_element")
      (element && element.options) ? element.options.map { |o| o.element.inner_html } : []
    end
  end
end
PageObject.register_widget :bool_list, BoolList, :select

请注意,所有定位器都与 select 列表相关。同样,请注意我们使用 accessor_methods 将额外的方法添加到页面对象。

然后页面对象将使用 bool_list 访问器方法。请注意,标识符用于定位 select 元素,我们说它是小部件的基本元素。

class MyPage
  include PageObject

  bool_list(:gender, title: 'Gender')
  bool_list(:nationality, title: 'Nationality')
end

页面现在可以调用以下方法:

page.gender_btn_element.click
page.gender_btn_element.exists?
page.gender
page.gender = 'Female'
page.gender_options

page.nationality_btn_element.click
page.nationality_btn_element.exists?
page.nationality
page.nationality = 'Barbados'
page.nationality_options