Class: RuboCop::Cop::Gusto::RspecDateTimeMock

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/gusto/rspec_date_time_mock.rb

Overview

Never mock time in specs. Use Rails Testing Time Helpers (eg ‘freeze_time` and `travel_to`) instead. .and_call_original is allowed.

Examples:

# bad
context 'time specific tests' do
  before { allow(Time).to receive(:now).and_return(current_time) }
  it 'does stuff in a fixed time' do
    subject
  end
end

# good
context 'time specific tests' do
  it 'does stuff in a fixed time' do
    freeze_time do
      subject
    end
  end
end

Constant Summary collapse

CLASSES =
Set[
  :Date,
  :Time,
  :DateTime
].freeze
MSG =
"Don't mock #{CLASSES.join('/')} directly. Use Rails Testing Time Helpers (eg `freeze_time` and `travel_to`) instead.".freeze
RESTRICT_ON_SEND =
%i(to).freeze

Instance Method Summary collapse

Instance Method Details

#and_call_original?(node) ⇒ Object



37
38
39
# File 'lib/rubocop/cop/gusto/rspec_date_time_mock.rb', line 37

def_node_search :and_call_original?, <<~PATTERN
  (send _ :and_call_original)
PATTERN

#on_send(node) ⇒ Object



59
60
61
62
63
64
65
66
67
68
# File 'lib/rubocop/cop/gusto/rspec_date_time_mock.rb', line 59

def on_send(node)
  time_mock?(node) do
    # Allow usages that explicitly call `.and_call_original` after `receive`
    # Example: allow(Time).to receive(:parse).and_call_original
    receive_chain = node.first_argument
    return if and_call_original_in_chain?(receive_chain)

    add_offense(node)
  end
end

#time_mock?(node) ⇒ Object

Matches allow/expect with a time class (or chain) receiver and a ‘receive` or `receive_message_chain` Examples matched:

allow(Time).to receive(:now)
allow(Time.zone).to receive(:now)
allow(Time).to receive_message_chain(:zone, :now)
expect(Date.today).to receive(:wday)


48
49
50
51
52
53
54
55
56
57
# File 'lib/rubocop/cop/gusto/rspec_date_time_mock.rb', line 48

def_node_matcher :time_mock?, <<~PATTERN
  (send
    (send nil? {:allow :expect} #rooted_in_time_class?)
    :to
    {
      (send (send nil? :receive _) ...)
      (send (send nil? :receive_message_chain ...) ...)
    }
  )
PATTERN