Prefer Explicit Cucumber Tests

An Inexact Test

Innocently enough, one of our developers added this feature, which passes:

  Scenario: Create Field
    When I manage the "acme" org
    And I go to the user field management list for "acme"
    And I click "New"
    And I set the following values
      | Name     | Test Field |
      | Required | true       |
    And I click the "Create" button
    Then I should see "Test Field"
    And I should see "test_field"
    And I should see "Yes"

Note: for now I am not going to discuss the other improvements that could be done with this feature (e.g., to remove the “click” steps).

Unfortunately, the actual page looked as follows (using save and open page):

Name        Required?  Key 	
First name  Yes        first_name
Last name   Yes        last_name
Test Field  No         test_field

Sure enough, the text “Yes” was indeed on the page, given the step was defined simply as shown below. However, the intent of the test was actually not correctly followed in the code.

Then(/^I should see "(.*?)"$/) do |text|
  expect(page).to have_text(text)
end

An Explicit Test

So one way to ensure the proper data appears in the proper place on the page, especially when it is in a table, is to do the following.

Add an ID to the page location:

    %table
      %thead
        %tr
          %th.text-center Name
          %th.text-center Required?
          %th.text-center Key
          %th.text-center
      %tbody
        - user_fields.each do |field|
          %tr{id: dom_id(field)}
            %td.text-center= field.name
            %td.text-center
              -if field.required
                Yes
              -else
                No
            %td.text-center= field.key

Change the feature to expect the text exists in the context of the record:

  Scenario: Create New Field
    Given I follow "User Fields" in the sidebar
    And I follow "New Field"
    And I set the following values
      | Name     | Zodiac Sign |
      | Required | true        |
    And I click the "Create" button
    And I should see the following user field:
      | name        | required | key         |
      | Zodiac Sign | Yes      | zodiac_sign |

And define a step something like this:

Then(/^I should see the following user field:$/) do |table|
  # table is a table.hashes.keys # => [:name, :required, :key]
  field = UserField.find_by(name: field_name)
  dom_id = "user_field_#{field._id}"
  table.hashes.each do |row|
    dom_id = dom_id_for_field(row[:name])
    within("tr##{dom_id}") do
      expect(page).to have_text(row[:key])
      expect(page).to have_text(row[:required])
    end
  end
end

Test Your Test!

I also like to check my tests! That is, go to the code where the text “Yes” is defined, and change it to something else. If your tests still pass, you know your test is flawed!

Summary

By adding a “findable” id to the output, you can more exclusively assert some text is on the page in the correct location!

Other approaches

  • ensure you eliminate the other non-essential elements from the page, so there are no “false positives”
  • Check for a very bizarre string that will not accidentally appear, like “Zebra Fangs”

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.