Skip to content

Commit

Permalink
Modernize time steps
Browse files Browse the repository at this point in the history
The time steps now fall back to the ActiveSupport time function if the
timecop gem is not present.
Moved the time steps from timecop.rb to time.rb and deprecated importing
timecop.rb
  • Loading branch information
nhasselmeyer committed Aug 12, 2020
1 parent a952ed8 commit 063b4f0
Show file tree
Hide file tree
Showing 17 changed files with 184 additions and 89 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 2.6.0
- The time steps do now work with the time helpers in ActiveSupport 4.1+ if the timecop gem is not included in the bundle. Please note that the two approaches branch. While ActiveSupport will freeze the time, Timecop will keep it running.
- The steps in the file `spreewald/timecop.rb` file were moved to `spreewald/time.rb` and importing `spreewald/timecop` directly is deprecated now.


## 2.5.0
- Add a set of steps to control browser tabs (Selenium only):
* `I open ... in a new browser tab`
Expand Down Expand Up @@ -32,7 +37,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html

## 2.2.4
- Fix "..." field should have the error "..." test by removing old should syntax
- Add single-line mail step to READNE
- Add single-line mail step to README

## 2.2.3
- Fix 'the window should be titled' step - closes: [#102](https://github.com/makandra/spreewald/issues/102)
Expand All @@ -52,7 +57,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html

## 2.2.0
- Add a new step `I should( not)? see a link labeled "STRING"`.
- Refer to Capybara 3's new flag `Capybara.default_normalize_ws = true` in the READNE,
- Refer to Capybara 3's new flag `Capybara.default_normalize_ws = true` in the README,

## 2.1.3
The `I should(not )? see /REGEXP/` step no longer refuses slashes as part of the regular expression. You can thus match full domains and more.
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,14 @@ the step definitions.
See [this article](https://makandracards.com/makandra/763-cucumber-step-to-match-table-rows-with-capybara) for details.


### timecop_steps.rb
### time_steps.rb

Steps to travel through time using [Timecop](https://github.com/jtrupiano/timecop).
Steps to travel through time

See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps-to-travel-through-time-with-timecop) for details.
This uses [Timecop](https://github.com/jtrupiano/timecop) or Active Support 4.1+ to stub Time.now / Time.current.
The user is responsible for including one of the two gems.

Please note that the two approaches branch. While ActiveSupport will freeze the time, Timecop will keep it running.


* **When the (date|time) is "?(\d{4}-\d{2}-\d{2}( \d{1,2}:\d{2})?)"?**
Expand All @@ -317,14 +320,16 @@ See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps
Given the time is 13:40


* **When it is (\d+|a|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)**
* **When it is (\d+|an?|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)**

Example:

When it is 10 minutes later
When it is a few hours earlier




### web_steps.rb

Most of cucumber-rails' original web steps plus a few of our own.
Expand Down
5 changes: 4 additions & 1 deletion lib/spreewald/all_steps.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# coding: UTF-8
require 'rspec/matchers'

ALREADY_LOADED_FILES = %w[all_steps timecop_steps]

Dir[File.join(File.dirname(__FILE__), '*_steps.rb')].each do |f|
name = File.basename(f, '.rb')
unless name == 'all_steps'

unless ALREADY_LOADED_FILES.include?(name)
require "spreewald/#{name}"
end
end
102 changes: 102 additions & 0 deletions lib/spreewald/time_steps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# coding: UTF-8


# Steps to travel through time
#
# This uses [Timecop](https://github.com/jtrupiano/timecop) or Active Support 4.1+ to stub Time.now / Time.current.
# The user is responsible for including one of the two gems.
#
# Please note that the two approaches branch. While ActiveSupport will freeze the time, Timecop will keep it running.
# FILE_COMMENT_END

major_minor_rails_version = defined?(ActiveSupport) ? [ActiveSupport::VERSION::MAJOR, ActiveSupport::VERSION::MINOR] : [0, 0]
is_at_least_rails_4_1 = (major_minor_rails_version <=> [4, 1]) != -1

if defined?(Timecop) || is_at_least_rails_4_1

module TimeHelpers

# When you have to make your rails app time zone aware you have to go 100%
# otherwise you are better off ignoring time zones at all.
# https://makandracards.com/makandra/8723-guide-to-localizing-a-rails-application

def use_timezones?
active_record_loaded = defined?(ActiveRecord::Base)
(!active_record_loaded || ActiveRecord::Base.default_timezone != :local) && Time.zone
end

def parse_time(str)
if use_timezones?
Time.zone.parse(str)
else
Time.parse(str)
end
end

def current_time
if use_timezones?
Time.current
else
Time.now
end
end

if defined?(Timecop)
# Emulate ActiveSupport time helper methods with Timecop - don't rename these methods
def travel(duration)
Timecop.travel(current_time + duration)
end

def travel_to(date_or_time)
Timecop.travel(date_or_time)
end

def travel_back
Timecop.return
end
else
require 'active_support/testing/time_helpers'
include ActiveSupport::Testing::TimeHelpers
end

end

World(TimeHelpers)

# Example:
#
# Given the date is 2012-02-10
# Given the time is 2012-02-10 13:40
When /^the (?:date|time) is "?(\d{4}-\d{2}-\d{2}(?: \d{1,2}:\d{2})?)"?$/ do |time|
travel_to parse_time(time)
end.overridable

# Example:
#
# Given the time is 13:40
When /^the time is "?(\d{1,2}:\d{2})"?$/ do |time_without_date|
travel_to parse_time(time_without_date) # date will be today
end.overridable

# Example:
#
# When it is 10 minutes later
# When it is a few hours earlier
When /^it is (\d+|an?|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)$/ do |amount, unit, direction|
amount = case amount
when 'a', 'an'
1
when 'some', 'a few'
10
else
amount.to_i
end
amount = -amount if direction == 'earlier'
travel amount.send(unit)
end.overridable

After do
travel_back
end

end
82 changes: 6 additions & 76 deletions lib/spreewald/timecop_steps.rb
Original file line number Diff line number Diff line change
@@ -1,79 +1,9 @@
# coding: UTF-8


# Steps to travel through time using [Timecop](https://github.com/jtrupiano/timecop).
#
# See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps-to-travel-through-time-with-timecop) for details.
# nodoc
# FILE_COMMENT_END

warn <<-WARNING
Warning: The file spreewald/timecop_steps.rb is deprecated. It was moved to
spreewald/time_steps.rb. Please require the new file instead.
WARNING

if defined?(Timecop)

module TimecopHarness

# When you have to make your rails app time zone aware you have to go 100%
# otherwise you are better off ignoring time zones at all.
# https://makandracards.com/makandra/8723-guide-to-localizing-a-rails-application

def use_timezones?
active_record_loaded = defined?(ActiveRecord::Base)
(!active_record_loaded || ActiveRecord::Base.default_timezone != :local) && Time.zone
end

def parse_time(str)
if use_timezones?
Time.zone.parse(str)
else
Time.parse(str)
end
end

def current_time
if use_timezones?
Time.current
else
Time.now
end
end

end

World(TimecopHarness)

# Example:
#
# Given the date is 2012-02-10
# Given the time is 2012-02-10 13:40
When /^the (?:date|time) is "?(\d{4}-\d{2}-\d{2}(?: \d{1,2}:\d{2})?)"?$/ do |time|
Timecop.travel(parse_time(time))
end.overridable

# Example:
#
# Given the time is 13:40
When /^the time is "?(\d{1,2}:\d{2})"?$/ do |time_without_date|
Timecop.travel(parse_time(time_without_date)) # date will be today
end.overridable

# Example:
#
# When it is 10 minutes later
# When it is a few hours earlier
When /^it is (\d+|a|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)$/ do |amount, unit, direction|
amount = case amount
when 'a'
1
when 'some', 'a few'
10
else
amount.to_i
end
amount = -amount if direction == 'earlier'
Timecop.travel(current_time + amount.send(unit))
end.overridable

After do
Timecop.return
end

end
require 'spreewald/time_steps'
12 changes: 9 additions & 3 deletions lib/spreewald_support/tolerance_for_selenium_sync_issues.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,28 @@ class Patiently
WAIT_PERIOD = 0.05

def patiently(seconds, &block)
started = Time.now
started = monotonic_time
tries = 0
begin
tries += 1
block.call
rescue Exception => e
raise e unless retryable_error?(e)
raise e if (Time.now - started > seconds && tries >= 2)
raise e if (monotonic_time - started > seconds && tries >= 2)
sleep(WAIT_PERIOD)
raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == started
raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if monotonic_time == started
retry
end
end

private

def monotonic_time
# We use the system clock (i.e. seconds since boot) to calculate the time,
# because Time.now may be frozen
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

def retryable_error?(e)
RETRY_ERRORS.include?(e.class.name)
end
Expand Down
2 changes: 2 additions & 0 deletions support/step_definition_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def initialize(filename)
end

def to_markdown
return '' if @comment =~ /\bnodoc\b/

spaced_comment = "\n\n" + @comment if @comment

<<-TEXT
Expand Down
3 changes: 2 additions & 1 deletion tests/rails-3_capybara-1/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ group :test do
gem 'selenium-webdriver'
gem 'rspec-rails'
gem 'spreewald', :path => '../..'
end
gem 'timecop'
end
2 changes: 2 additions & 0 deletions tests/rails-3_capybara-1/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ GEM
sqlite3 (1.3.8)
thor (0.18.1)
tilt (1.4.1)
timecop (0.9.1)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
Expand All @@ -175,6 +176,7 @@ DEPENDENCIES
selenium-webdriver
spreewald!
sqlite3
timecop

BUNDLED WITH
1.17.3
3 changes: 2 additions & 1 deletion tests/rails-3_capybara-2/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ group :test do
gem 'selenium-webdriver'
gem 'rspec-rails'
gem 'spreewald', :path => '../..'
end
gem 'timecop'
end
2 changes: 2 additions & 0 deletions tests/rails-3_capybara-2/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ GEM
sqlite3 (1.3.8)
thor (0.18.1)
tilt (1.4.1)
timecop (0.9.1)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
Expand All @@ -184,6 +185,7 @@ DEPENDENCIES
selenium-webdriver
spreewald!
sqlite3
timecop

BUNDLED WITH
1.17.3
1 change: 1 addition & 0 deletions tests/rails-4_capybara-3/features/time_steps.feature
2 changes: 1 addition & 1 deletion tests/rails-6_capybara-3/.ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.1
2.6.6
1 change: 1 addition & 0 deletions tests/rails-6_capybara-3/features/time_steps.feature
2 changes: 2 additions & 0 deletions tests/shared/app/views/static_pages/time.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
= "The current date is #{Time.current.strftime("%Y-%m-%d")}."
= "The current time is #{Time.current.strftime("%H:%M")}."
1 change: 1 addition & 0 deletions tests/shared/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
get '/static_pages/tab_1', to: 'static_pages#tab_1'
get '/static_pages/tab_2', to: 'static_pages#tab_2'
get '/static_pages/tab_3', to: 'static_pages#tab_3'
get '/static_pages/time', to: 'static_pages#time'
get '/static_pages/visibility', to: 'static_pages#visibility'
get '/static_pages/within', to: 'static_pages#within'

Expand Down
Loading

0 comments on commit 063b4f0

Please sign in to comment.