How to use plural Page-Object widgets

66 views Asked by At

I'm using the "PageObject" gem and Ruby and created a widget using the "page-object wiki" as a reference.

I cannot find plural elements, meaning I can't find an array of elements.

If the tag for my widget is some-widget, this works:

some_widget_element(id: 'some-id')

But this does NOT work:

some_widget_elements(id: 'some-id')

I am trying to find multiple elements by id, which is how the page is structured.

I get the error:

NoMethodError: undefined method 'new' for nil:NilClass

Is there anything I need to do/add to my Widget class?

1

There are 1 answers

0
Justin Ko On

Registering a widget will define both:

  • The page-level accessor as well as
  • The nested element locator

As an example, let's assume the following HTML:

<html>
  <body>
    <div>empty</div>
    <div>
      <some-widget id="some-id">a</some-widget>
      <some-widget id="some-id">b</some-widget>
      <other id="some-id">c</other>
    </div>
    <some-widget id="some-id">d</some-widget>
  </body>
</html>

As well, that we have registered the widget:

class SomeWidgetClass < PageObject::Elements::Element
  PageObject.register_widget :some_widget, self, :element
end

Nested Element

The created nested element method is in the form "{widget_tag}_elements".

class TestPage
  include PageObject

  def nested_in_page
    some_widget_elements(id: 'some-id', tag_name: 'some-widget')
  end

  def nested_in_element
    div_elements[1].some_widget_elements(id: 'some-id', tag_name: 'some-widget')
  end
end

page = TestPage.new(browser)
p page.nested_in_page.map(&:text)
#=> ["a", "b", "d"]
p page.nested_in_element.map(&:text)
#=> ["a", "b"]

Page-Level Accessor

By default, the page-level accessor for returning an Array of all matching widgets is based on the widget's class name. This differs from the singular accessor method, which you define when registering the widget. Specifically, the method name is defined by the following expression:

def self.plural_form
  "#{self.to_s.split('::')[-1].
      gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
      gsub(/([a-z\d])([A-Z])/, '\1_\2').
      tr("-", "_").
      downcase}s"
end

In our example, the SomeWidgetClass class would create a some_widget_classs method:

class TestPage
  include PageObject

  some_widget_classs(:my_widgets, id: 'some-id', tag_name: 'some-widget')
end

page = TestPage.new(browser)
p page.my_widgets_elements.map(&:text)
#=> ["a", "b", "d"]

You can override the accessor name by defining the plural_form for your widget. The following renames the method to plural_widgets:

class SomeWidgetClass < PageObject::Elements::Element
  def self.plural_form
    :plural_widgets
  end

  PageObject.register_widget :some_widget, self, :element
end

class TestPage
  include PageObject

  plural_widgets(:my_widgets, id: 'some-id', tag_name: 'some-widget')
end

The actual usage of the page does not change - ie is still page.my_widgets_elements.