Is Ruby compatible with strict Page Object Pattern?

390 views Asked by At

I have built various Test Automation frameworks using the Page Object Pattern with Java (https://code.google.com/p/selenium/wiki/PageObjects).

Two of the big benefits I have found are:

1) You can see what methods are available when you have an instance of a page (e.g. typing homepage. will show me all the actions/methods you can call from the homepage)

2) Because navigation methods (e.g. goToHomepage()) return an instance of the subsequent page (e.g. homepage), you can navigate through your tests simply by writing the code and seeing where it takes you.

e.g.

WelcomePage welcomePage = loginPage.loginWithValidUser(validUser);
PaymentsPage paymentsPage = welcomePage.goToPaymentsPage();

These benefits work perfectly with Java since the type of object (or page in this case) is known by the IDE.

However, with Ruby, the object type is not fixed at any point and is often ambiguous to the IDE. Therefore, I cannot see how you can realise these benefits on an automation suite built using Ruby (e.g. by using Cucumber).

Can anyone show me how you would use Ruby with the Page Object Pattern to gain these benefits?

3

There are 3 answers

0
Charlie S On

From some further investigation, it looks like the initial requirement can be fulfilled using instance variables:

Given(/^I am on the launch page$/) do
  @launch_page ||= LaunchPage.new
end

When(/^I open the set alarm time page$/) do
  @set_alarm_page = @launch_page.goto_set_alarm_page
end

When(/^I open our apps from the home page$/) do
  @launch_page.navigation_toolbar.open_our_apps
end

Then(/^I should see the homepage alarm time is (\d+)$/) do |alarm_time|
  alarm_time_actual = @launch_page.get_alarm_time
  assert_equal(alarm_time, alarm_time_actual)
end

As long as somewhere on the step definition class you explicitly create a new page object (in the above example: LaunchPage.new), then all subsequent pages will appear and provide intellisense method/property values.

2
Rahoul Baruah On

I use Spinach instead of Cucumber - it's almost identical, but the steps are enclosed within a class that is unique to that feature file - so there's no leakage of objects outside of the current scope.

https://github.com/codegram/spinach

1
Charlie S On

From chatting to colleagues I suspect the following might be the best solution (but please post an alternative answer if a better solution exists):

When(/^I buy a movie from the movie page$/) do
  movie_page = MoviePage.new
  movie_page.buyMovie("Test Movie")
  purchase_page = PurchasePage.new
  purchase_page.confirmPurchase
end

So in the example above we are NOT returning instances of the subsequent page when navigating around the page (since the page returned would simply be an unknown type of object). Additionally, we need to create a new instance of any page we are on (using ".new") so that at least we can gain the intellisense benefits of typing "movie_page." and seeing what actions/methods are available from that page.

Does anyone have any better solutions?