This Tech Bite was brought to you by Amira Džanović, Test Engineer at Atlantbh.
Tech Bites are tips, tricks, snippets or explanations about various programming technologies and paradigms, which can help engineers with their everyday job.
Method chaining using Capybara and SitePrism
What are Capybara and SitePrism?
Capybara is a Ruby library that is used for automating web pages in concert with an underlying web-based driver. It consists of a user-friendly DSL, used to describe actions that are then executed by the web driver.
While the Capybara syntax is very easily readable as-is, it can be improved upon to produce tests that are more DRY. This is where the SitePrism gem comes in – a DSL on top of Capybara, used for implementing the Page Object Model. Out of the box, it comes with predefined classes for many common features of websites, such as pages and sections.
Finally, to produce easily maintainable and completely readable tests, we can use method chaining with these tools. So, on an example of a page consisting of a login form and search function, here’s how we would go about doing that.
Setting up page objects
Firstly, we need to define the elements that make up the pages in the flow we are testing. Starting with the homepage, we will first define the URL and elements present, using SitePrism’s set_url and element methods:
class HomePage < SitePrism::Page set_url 'https://www.testsite.com' element :go_to_login, 'some-login-link' element :search_bar, 'some-search-bar' element :search_button, ‘some-search-icon' end
Notice we are inheriting from SitePrism::Page class, a built-in abstract class within the SitePrism gem. It contains methods used for loading pages as well as checking different attributes, such as if a page is displayed, secure, on the expected URL, etc.
After setting up the home page, we do the same for the login page:
class LoginPage < SitePrism::Page set_url 'https://www.testsite.com/login' element :name, 'some-username-field' element :password, 'some-password-field' element :login_button, 'some-login-button' end
Now that we’ve described these different views on our page, we can, likewise, describe actions that we want to be performed on each. We will add these methods to our page objects, so starting with the Homepage, let’s define a way to access the login form:
def go_to_login_page do go_to_login.click return(LoginPage.new) end
Notice that our method returns a new instance of the LoginPage object. By doing this we avoid having to instantiate a new LoginPage within the test itself.
Then we add the login method to the LoginPage class, as well as a search method to the HomePage class:
#In the LoginPage class: def log_in_user(user_name, user_password) do fill_in(name, with: user_name) fill_in(password, with: user_password) login_button.click return(HomePage.new) end
#In the HomePage class: def search_for_something(query) do fill_in(search_bar, with: query) search_button.click return(SearchResults.new) end
Method chaining in action
Finally, in our spec, we need to require the objects we’ve created and write some tests. In our case, the user should be able to log in and get search results for their query:
require_relative './page_objects/HomePage.rb' require_relative './page_objects/LoginPage.rb' describe 'test' do it 'should login and return search results' do @app.go_to_login_page .log_in_user('1337_Jane', 'aLamePassword420') .search_for_something('Tasty Donuts w chocolate glaze') expect(page).to have_content('Some results related to the search query') end end