Skip to content

Instantly share code, notes, and snippets.

@tgaff
Forked from h-parekh/site-prism.md
Last active December 14, 2022 21:40
Show Gist options
  • Save tgaff/b4c665c867c1886ac4f04403bc1761d0 to your computer and use it in GitHub Desktop.
Save tgaff/b4c665c867c1886ac4f04403bc1761d0 to your computer and use it in GitHub Desktop.
What, why and a little bit of how to use site-prism

site prism

Page Object Model gem for ruby Page Objects are like react-components for integration spec code. They let you componentize pages or parts of pages so you don't use css-selectors every where.

If you have page.find('button', text: 'update section') in a lot of tests, when the PM says it should be 'Change Section' you have a lot of changes to make.
By sticking this in the page-object it limits the needed scope of change to just that POM and possible the one test that regression checked this.

pages

Let you define elements on your page

class Login < SitePrism::Page
  element :username, '#username'
  element :password, '#password'
  element :sign_in_button, 'button'
end

Then use it in your tests

  @login = Login.new
  @login.load
  expect(@login).to have_username
  @login.user_name.set 'sam@example.com'
  @login.password.set 'password'
  @login.sign_in_button.click
  expect(@page).to have_content 'Thanks for signing in Sam'

capybara options

capybara options like text just pass straight through.

class HeaderSection < SitePrism::Section
  set_default_search_arguments '#header'
  element :header_logo, 'div#logo'
  element :courses, 'a', text: 'COURSES'
  element :departments, 'a', text: 'DEPARTMENTS'
  element :affordability, 'a', text: 'AFFORDABILITY'
  element :users, 'a', text: 'USERS'
  element :help, 'button', text: 'GET HELP'
end

# also possible to pass in line in test code

@page.courses(text: 'ACCT').click

sections

You can break more complicated stuff into sections

class Menu < SitePrism::Section
  element :search, 'a.search'
  element :images, 'a.image-search'
  element :maps, 'a.map-search'
end

class Home < SitePrism::Page
  section :menu, Menu, '#gbx3'
end

Don't feel like you need to over-componentize though. - it doesn't need to be as scoped down as far as a react component would be. You can partition a page into sections, that repeat on the same page or across different pages: For example: Sections repeating on same page: search results, list of courses Sections repeating on different pages: header, menu, footer, facet navigation

methods (PORO)

Pages and sections are just ruby classes

  • great place to put common methods that you might use a lot
class LogInPage < SitePrism::Page
  set_url '/session/new'
  element :login, 'div#login'
  element :email_field, 'input[id="user_email"]'
  element :password_field, 'input[id="user_password"]'
  element :submit_button, 'button', text: 'LOGIN'
  element :flash_message, 'div.alert'

  def visit_and_login_as(email, password)
    load
    email_field.set email
    password_field.set password
    submit_button.click
    wait_until_page_has_flash_message, text: 'Success'
    page.has_content? 'div#menu'  
  end
end

# now in my test code I just
let(:user) { create(:user) }

before do
  LoginPage.new.visit_and_login_as(user.email, 'password')
end

key benefits

  1. Selectively assert on specific elements of a page or a section, based on the signed in user permisssions, feature flags and application state
  2. Organize and DRY test code
  3. Reduces integration fragility - uses the waiting functionality of capybara
  4. Improve test readability
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment