1

I am using the PageObject pattern, which abstracts HTML details away from the top-level of the test. I am doing this using the SitePrism gem.

In my example, I have a home page (HomePage.rb):

class HomePage < SitePrism::Page
  set_url ENV['BASE_URL']
  section :header, HeaderSection, "div[class='headerSection']"

which refers to a common page section, HeaderSection (HeaderSection.rb):

class HeaderSection < SitePrism::Section
  element :sign_in_button, "a[class='signIn']"

and a step definition for my tests (login.rb):

And(/^I am not logged in/) do
  @home_page = HomePage.new    # actually, this is specified in env.rb     
  expect(@home_page.header).to have_sign_in_button
end

Instead of exposing the web element to the step definition, I want to encapsulate this within a class method of HomePage. It seems that the best way to do that is to put the assertion into a class method within HomePage itself (HomePage.rb):

def amILoggedIn
  expect(header).to have_sign_in_button
end

The above assumes that I am also using include RSpec::Matchers.

My method would then be the only thing exposed to the step definition (login.rb):

And(/^I am not logged in/) do
  @home_page.amILoggedIn
end

As part of SitePrism, the sign_in_button element has its own built-in methods to check for its presence, which is:

header.has_sign_in_button?

Question

In terms of best practice, which is the most recommended way of writing this assertion within the amILoggedIn method (even though it appears they both use the same instruction),

expect(header).to have_sign_in_button

or

header.has_sign_in_button?
Wayne Conrad
  • 103,207
  • 26
  • 155
  • 191
jimjamz
  • 59
  • 6
  • I have removed the question that is primarily opinion based (but in my opinion, yes, this is a good pattern to use. – Wayne Conrad Jul 22 '17 at 13:18

2 Answers2

2

expect(header).to have_sign_in_button and header.has_sign_in_button? do two different things. The first is an assertion (raises an exception if it fails) and the second just returns a boolean response. If what you want is an assertion you could assert on the boolean response assert header.has_sign_in_button? or expect(header.has_sign_in_button?).to be true but the failure message from have_sign_in_button is going to be a lot more descriptive.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • Hi Thomas. Thanks for your answer. In my own personal opinion, I do prefer the `expect` assertion myself, as it is also reads better than the `assert` alternative, especially to the uninitiated, who are not familiar Ruby test code. – jimjamz Jul 24 '17 at 12:38
  • You can get the best of both worlds in [Capybara Test Helpers](https://capybara-test-helpers.netlify.app/guide/essentials/assertions), where assertions can be written concisely, and are powered by RSpec expectations which provide good descriptive messages. – Maximo Mussini Nov 23 '20 at 02:27
0

Old question but providing updated answer

Given SitePrism now uses implicit waiting by default as Thomas has said you've got two different method signatures, and two different outputs.

Also dependent on who you speak to, it is considered poor practice to include the matchers in a variety of places. Using Cucumber with SitePrism gives you a nice separation of concerns to perform the testing in the Cucumber World (step_definitions), and isolate all other modelling concerns to the support code.

Using SitePrism as described by the official docs will allow you (when using cucumber), to access all rspec methods in the cucumber world, and test easily and effectively.

Luke Hill
  • 460
  • 2
  • 10