Search code examples
rubyrefactoringpage-object-gem

Cleaning up massive amount of PageObject elements


Each of our page objects has around 80-100 PageObject elements defined. This is a byproduct of a very data centric application and I don't see that changing any time soon. We have many text fields, select lists, buttons, and menus. I want to clean up these somehow and put them somewhere, but the things I've thought about don't seem very clean.

Ideas:

  • Move elements for each PageObject into a corresponding module and include that module into a single PageObject only
  • create a YAML config file, with the mapping of element_type => element_name => element_id and then call the corresponding element methods using metaprogramming
  • Utilize the upcoming PageObject sections feature to create different "panels" within each page and then include those Panels into the page.

The first solution has the problem that each module can be included in other classes if somebody doesn't pay attention. It's not restricted to the single class

The second solution seems slow and not very "rubular", along with being confusing to update elements for those new to the project

The third solution seems like the best, but like the first solution, you could potentially include Sections into a class that they don't belong in.

What other way can I move the definition of these elements out of the class so that our class is cleaner, shorter, easier to read, and defined to Ruby Specifications (i.e. the Ruby Style Guide). They really just seem like config data rather than ruby code, so I feel like they don't belong in the class. Especially when we have 80+ elements in each class.


Solution

  • I don't see why you wouldn't keep the elements in the page object class. That's kind of the point of the class, right? If they're shared across multiple pages, then I understand putting them in a module and mixing in. But why abstract the unique elements on that page away from the page class?

    But if you're absolutely going to do this, I'd think this is the best option:

    Move elements for each PageObject into a corresponding module and include that module into a single PageObject only

    There are ways you could ensure these modules are included only in the classes you expect. I have Module#included in mind. Something like:

    module MyPageElements
      def self.included cls
        raise "Expected to be included on MyPage, got: #{cls}" unless cls == MyPage
      end
    
      # ... elements ...
    end
    

    create a YAML config file, with the mapping of element_type => element_name => element_id and then call the corresponding element methods using metaprogramming

    Seems like this would be a headache to bring new, unfamiliar people up to speed on the code. Ultimately, I agree that it's just too un-Ruby like.

    Utilize the upcoming PageObject sections feature to create different "panels" within each page and then include those Panels into the page.

    Since I've just barely looked at this (thanks for linking me to the PR), I don't feel like I can speak to its efficacy.