TA Basics: How to use the helper files

When you just start with test automation, you most likely search and interact with elements within your `*_steps.rb` files (the files that contain the precondition, interaction and validation steps). So most likely across the steps, you have repeatedly located and interacted with the same elements a couple of times. And as long as your test suite is small, adjusting it only takes a small bit of time and it works, so who cares, right?  But now imagine you have a 100 scenario's, 100+ (precondition, interaction and validation) steps. And in a bunch of them you've locate the same element. But because of a change in the website this button cannot be found anymore. Are you going to adjust this in every line in your code to fix? Your answer should be: "NO!". You could use nested steps, but this becomes really confusing really fast and is not a good practice. So let's have a look at a proper solution, the helper files.

Structure

We basically define four main layers in our test suite setup.
  1. Scenario's (human readable)
  2. Step definitions (match between scenario's to helpers)
  3. Helpers (element definition, functions and business logic)
  4. Configurations (contain url's, users, and other configurations)
Our scenario's should stay as clean as possible as explained in an earlier post. This way scenario's stay readable for everyone that and can therefore also serve as documentation. For example, take this scenario:
When the user completes registration
This is really easy to understand for anyone, no code/scripting knowledge required. Our step definitions will contain the link between this human readable scenario and a piece of code. So here it becomes a bit more codey but is still fairly easy to follow for most people (see final solution later on). I usually start with adding all business logic/individual steps, into the step definition as comment. That way I know what needs to be done:
When 'the user completes registration' do
      # fill the form 
          # set username
          # set password
          # select gender
          # etc.
     # submit the form
end
But if we define all these interactions here and you have another scenario where you need to fill in invalid details, you're basically finding and interacting with the same element twice. And duplication is what we want to prevent, we want to re-use as much as possible. Therefore let's move all this maintanance to one location and the location is the helper file. That way we can re-use all element interaction and only have one location that needs to be updated when elements or logic/order changes.

The helper file

I took the user registration as an example because it's already present in the generated test automation suite. When you open the files you will already see the final solution.
For the scenario, open the file `.\features\2_account.feature` and look at line 31. For the interaction step open the file `.\features\step_definitions\account_steps.rb` line 54. And the helper is located in file `.\features\helpers\registration_helper.rb`

A quick overview of how this helper file is constructed:
  • module Register - Is the name of the module
  • extend LapisLazuli - Shows that this module extends the lapis_lazuli gem
  • class << self - This is what it says
  • And then a bunch of defined functions

Functions

Technically all elements are being defined in a function which can be reused. (keep in mind this are elements from the testautomation.info training page so for your page you need to figure out which elements you need to define). 
At the top we start with elements that can be defined in one line of code. Then two elements that have a bit more code so we nicely split it into multiple lines for better readability. And last but not least a list of functions that are interacting with the elements listed above.

Now skip to the line that is matching with the one from the step definition file (Register.register_user).  We see this function:
def register_user Register.fill_form Register.submit_form end
And as you might understand by now, in this function we are pointing to two other functions. fill_form and submit_form (both located in the Register helper).

Fill_form

Let's look at fill_form and describe what we see:
def fill_form Register.username_field.set(User.get('username')) Register.password_field.set(User.get('password')) Register.gender_radio(User.get('gender')).click Register.select_experiences(User.get('experience').split(',')) Register.biography_field.set(User.get('biography')) Register.policy_checkbox.set((User.get('complete_all').to_i == 1)) end
As you can see, this function will fill in all the information on the form. What you might also have seen is that we're not redefining the element here, instead we refer to the element function we've defined at the top of this helper file. Just to pick out one as an example and read it back to front:
Register.username_field.set(User.get('username'))
This will try to get a username from the User helper (which on it's turn gets the name from the .\config\users.yml file), set the username in the username_field which we defined at the top of the Registration helper like this:
def username_field; browser.find(:element => {:name => 'username'}, :context => Register.form); end
When your team now decides that the website needs to change and the element will become `usr_name`, we only need to adjust the element at the top of the helper. All functions that are trying to find/interact with this element are now working again.

Submit_form

The second function is submit_form, which seems a bit overkill since it only performs a click on one element which could also have been covered in the step definition instead.
def submit_form Register.submit_button.click end
But there are two reasons why you might want to put this already into a seperate function. The first would be in case there is also a checkbox to agree with the terms and conditions. This checkbox click could then also be added to the submit_form function . And second, you could  also think about the difference between desktop click and mobile tap as described in one of my previous blogposts. In those cases it makes more sense to move it into a function because the click logic is than something you want to remove from the business logic so the steps stay clean and the function takes care of what kind of click it needs to be.

IRB

If you run your test suite with cucumber, all helpers will be loaded for you. Lapis_lazuli takes care of that. But what if you want to use the helper in IRB? The only thing you need to do, is load the helper file manually like you need to load the gem manually. Here is a small example how to use the helper in IRB. Before I started, I already navigated to the project folder before I started IRB. If you did not, you might need to enter the full path to the helper in the load command instead. 

I hope this post helped you to understand the need and usage of the helper files. If you have any question, feel free to contact me.

Comments

Popular posts from this blog

PowerShell - How to overcome Azure VM's fixed resolution limitation

TA Basics: Website Test Automation on mobile devices via Appium server

TA: Who doesn't like proxies? Me!