Bmoe
Bmoe

Reputation: 978

Re-Usable Components in Cheezy Page Object

I'm using cheezy page-object gem and cucumber.

I have page objects for an angular website and many pages contain angular ng-select element which is a dropdown. All of the ng-select elements are the same format for each page. The only thing that changes is the data and the id of the ng-select. I'd like to build some re-usable ng-select component that I can put in my page-objects as I have quite a few methods I use on the element.

class NGSelectComponent
  include PageObject

  def wrapper(id)
    element(:element, tag_name: 'ng-select', id: id)
  end

  def wrapper_text_field
    wrapper.text_field_element
  end

  def wrapper_span
    wrapper.span_element(class: ['ng-value-label','ng-star-inserted'])
  end

  def wrapper_value
    wrapper_span.text
  end

  def wrapper_values
    wrapper.div_elements
  end
end

As you can see the wrapper method is the ng-select element and it takes an id for the locator hash. This is as far as I got. I saw something like this but it looks like it only works for HTML elements.

How can I turn this into a re-usable component using page-object gem? As a sidenote I call my page objects using the on() method in my step definitions. So for example on(SomePage). I felt like that matters for however the solution turns out.

Upvotes: 0

Views: 109

Answers (1)

Justin Ko
Justin Ko

Reputation: 46846

Widgets and page sections are the 2 options for re-usable components. As you will likely want to setup getters/setters for the field, widgets are the better choice.

The widget could be defined like:

class NGSelectComponent < PageObject::Elements::Element
  def self.accessor_methods(accessor, name)   
    #
    # Define a getter
    #
    accessor.send(:define_method, "#{name}") do
      self.send("#{name}_element").value
    end

    #
    # Define a setter. Use "#{name}=" so that the widget can be used
    # in #populate_page_with
    # 
    #
    accessor.send(:define_method, "#{name}=") do |value|
      self.send("#{name}_element").set(value)
    end
  end

  def set(value)
    text_field_element.set(value)
  end

  def value
    text_field_element.value
  end

  def wrapper_text_field
    text_field_element
  end

  def wrapper_span
    span_element(class: ['ng-value-label','ng-star-inserted'])
  end

  def wrapper_value
    wrapper_span.text
  end

  def wrapper_values
    div_elements
  end

  PageObject.register_widget :ng_select, self, :element
end

Page objects would define the ng-select elements like any other accessor:

class TestPage
  include PageObject

  ng_select(:name, id: 'name')
end

Giving the page a getter/setter for the field - eg:

page = TestPage.new(browser)
page.populate_page_with(name: 'My Name')
p page.name
#=> "My Name"

Upvotes: 2

Related Questions