Migration Guide Capybara → Chemlab

Given the view:

_form.html

<form id="my-form">
    <label for="first-name">First name</label>
    <input type="text" name="first-name" data-testid="first_name" />

    <label for="last-name">Last name</label>
    <input type="text" name="last-name" data-testid="last_name" />

    <label for="company-name">Company name</label>
    <input type="text" name="company-name" data-testid="company_name" />

    <label for="user-name">User name</label>
    <input type="text" name="user-name" data-testid="user_name" />

    <label for="password">Password</label>
    <input type="password" name="password" data-testid="password" />

    <input type="submit" value="Continue" data-testid="continue"/>
</form>
Capybara Chemlab
before after

Key Differences

Page Library Design vs Page Object Design

Page Objects as implemented in the existing framework require you to define methods to perform actions on elements. (Usually one-liners)

def set_first_name(first_name)
  fill_element(:first_name, first_name)
end

def click_continue
  click_element(:continue)
end

it 'sets first name and clicks continue' do
  Page::Form.perform do |form|
    form.set_first_name('First Name')
    form.click_continue
  end
end

Page Libraries make this more efficient by providing methods based on the page’s elements, making extra methods unnecessary.

it 'sets first name and clicks continue' do
  Page::Form.perform do |form|
    form.first_name = 'First Name'  # sets the first_name
    form.continue  # clicks Continue
  end
end

Consider if we needed to validate the text of the First name field using Capybara. We’d need to add a one-liner to fetch the text:

def get_first_name
  find_element(:first_name).text
end

Page::Form.perform do |form|
  form.set_first_name('First Name')
  expect(form.get_first_name).to eq('First Name')
  form.click_continue
end

Instead, because the page library automatically creates methods from page elements, we can fetch the text by calling first_name without writing code to define the method ourselves:

Page::Form.perform do |form|
  form.first_name = 'First Name'
  expect(form.first_name).to eq('First Name')
  form.continue
end

Element Naming Convention

Since the element type is preserved within the Page Library, there is no need to specify a _field or _button suffix to the data-testid.

<!-- Before -->
<input type="text" name="first-name" data-testid="first_name_field" />
<input type="submit" name="continue" value="Continue" data-testid="continue-button" />

<!-- After -->
<input type="text" name="first-name" data-testid="first_name" />
<input type="submit" name="continue" value="Continue" data-testid="continue" />

This makes it much easier for Developers to write tests and contributes to testability since we can write the Page Library while we look at the UI.