Skip to content

Instantly share code, notes, and snippets.

@qpowell

qpowell/cukedates.md

Last active Aug 29, 2015
Embed
What would you like to do?
Handling Dates and Times in Cucumber

Handling Dates and Times in Cucumber

If you have to write an integration test that includes a specific date or time, there's an extra step you need to take to ensure that your tests don't break when the date/time changes. Take the following example for instance:

Scenario (cash_discounts_list.feature):

  Scenario: List the cash discounts sorted by status, type, end date
    Given there are some cash discounts
    When I list the "cash_discounts"
    Then I should see the following table
      | Type       | End Date   | Percentage | Status   |
      | Energy     | 10/15/2014 | 1.0%       | Active   |
      | Fertilizer | 10/16/2014 | 8.0%       | Active   |
      | Fertilizer | 10/19/2014 | 2.0%       | Active   |
      | Seed       | 10/22/2014 | 7.0%       | Inactive |

Step Definition:

Given(/^there are some cash discounts$/) do
  create_order_types
  FactoryGirl.create(:cash_discount, end_date: Date.today, percent_discount: 8, order_type: OrderType.find_by_name("Fertilizer"), active: true)
  FactoryGirl.create(:cash_discount, end_date: Date.today + 3.days, percent_discount: 2, order_type: OrderType.find_by_name("Fertilizer"), active: true)
  FactoryGirl.create(:cash_discount, end_date: Date.today + 6.days, percent_discount: 7, order_type: OrderType.find_by_name("Seed"), active: false)
  FactoryGirl.create(:cash_discount, end_date: Date.today - 1.days, percent_discount: 1, order_type: OrderType.find_by_name("Energy"), active: true)
end

If you were to run script/ci on 10/16/2014, these would pass. If you were to run them on 10/17/2014, these would fail. Why? Because Date.today no longer returns 10/16/2014. Using the timecop gem, we can "freeze time to a specific point" when we need to run a time-specific test. If you look at generic_steps.rb, you'll see that there's a step defined to make adding this to a scenario pretty trivial:

Given(/^the date and time is "(.*?)"$/) do |time|
  Chronic.time_class = Time.zone
  Timecop.freeze(Chronic.parse(time))
end

To make the test pass (no matter which date we run it on), we can update it like so:

  Scenario: List the cash discounts sorted by status, type, end date
    Given the date and time is "10/16/2014 10:00 AM"
    And there are some cash discounts
    When I list the "cash_discounts"
    Then I should see the following table
      | Type       | End Date   | Percentage | Status   |
      | Energy     | 10/15/2014 | 1.0%       | Active   |
      | Fertilizer | 10/16/2014 | 8.0%       | Active   |
      | Fertilizer | 10/19/2014 | 2.0%       | Active   |
      | Seed       | 10/22/2014 | 7.0%       | Inactive |

By default, once you use timecop to freeze the time, it remains that way. You can unfreeze timecop by using Timecop.return. To avoid having to include this in every single scenario, we've included it in features/support/env.rb in the After block so that it runs after each of the scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment