1

There is a discussion in our team if we should forbid exposing "ElementFinder" and "ElementArrayFinder" in our Page Objects.

The main reason is following quote by Simon Stewart. Page Objects Done Right - selenium conference 2014 (page.7)

If you have a WebDriver APIs in your test methods... You're doing it wrong.

SeleniumHQ/selenium/PageObjects https://github.com/SeleniumHQ/selenium/wiki/PageObjects

The approach is correct for transition functions that returns another Page Object or if multiple selections are happening on one Page so we can return Page and chain these calls.

But when we are doing something really simple there is a lot of boilerplate to write to test that element exist and have text.

Creating those mimic functions of "ElementFinder" does not make much sense to me. Most of the time its faster and more readable to expose element and use build-in functions of "ElementFinder" like ".getText()". Do you think its better make element private and expose only "getElementText()" function?

What is best practice do you forbid to expose "ElementFinder" and "ElementArrayFinder" in Page Objects?

Marcel Mandatory
  • 1,447
  • 13
  • 25

1 Answers1

1

We use cucumber so tests are divided between

  • features
  • step definitions
  • helpers
  • page files

All the logic and asserts are in step definitions and helpers. The step definitions invoke page methods when a screen value is needed. The page methods return POJOs. All details about finding elements are encapsulated in the page files. The reasons are obvious; when (not if) the page HTML changes you only have to make the fix in one place. Once you break encapsulation you have the start of a maintenance nightmare.

A pattern that I often use is to create a helper class e.g. OfficeInfo, to contain, say, all the td's in a tr for a table of offices. The page method would return

List<OfficeInfo>

i.e. one list element for each tr. The office information is now decoupled from the details of how that information is displayed on the page. If new td's are added you update class OfficeInfo, update the page method and insert the new step definition without impacting all the other places that OfficeInfo (but not the new td) is used.

Community
  • 1
  • 1
MikeJRamsey56
  • 2,779
  • 1
  • 20
  • 34
  • Page Objects have - selectors like element = $(".className") - functions like "fillEmail(email: string): PageObject" or "login(email: string, password: string): HomePage" We are using typescript and the question is if the selector should be always private as proposed in team? – Marcel Mandatory Nov 10 '16 at 23:32
  • I saw that your question was JavaScript and I gave a Java answer. But the rule still applies, don't expose your selectors outside of the page file. Functions are fine but keep the selectors encapsulated. – MikeJRamsey56 Nov 10 '16 at 23:43
  • When you have for example button element and want to test class, text and href then you create getter function for each? Isn't better to use element.getAttribute("class"), element.getText(), element.getAttribute("href"). You are creating extra function that just return the above with name like getElementText it does not make sense to me. What if page have plenty of elements instead of exposing just "n" variables you will make these "n" element variables private and expose "n * number of attributes you want to test" instead? – Marcel Mandatory Nov 11 '16 at 00:29
  • buttonElement.click() is an action. What behavior do you expect by clicking that button? Page files are concerned with actions on elements. The code that invokes page file functions should care only about the behavior. Login is a behavior. The details about what elements you type into and click are page actions that could change tomorrow. Encapsulate the page actions in a function that is independent of the actions but describes the desired behavior. – MikeJRamsey56 Nov 11 '16 at 00:39