Top Level Namespace

Defined Under Namespace

Modules: Granite, RuboCop Classes: GraniteGenerator

Instance Method Summary collapse

Instance Method Details

#have_projectorObject

Checks if the business action has the expected projector

Example:

“‘ruby is_expected.to have_projector(:simple) “`



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/granite/rspec/have_projector.rb', line 10

RSpec::Matchers.define :have_projector do |expected_projector|
  match do |action|
    @expected_projector = expected_projector
    @action_class = action.class
    @action_class._projectors.names.include?(expected_projector)
  end

  failure_message do
    "expected #{@action_class.name} to have a projector named #{@expected_projector}"
  end

  failure_message_when_negated do
    "expected #{@action_class.name} not to have a projector named #{@expected_projector}"
  end
end

#raise_validation_errorObject

Checks if code in block raises ‘Granite::Action::ValidationError`.

Modifiers:

  • ‘on_attribute(attribute)` – error relates to attribute specified;

  • ‘of_type` – checks the error has a message with the specified symbol;

Examples:

“‘ruby expect { code }.to raise_validation_error.of_type(:some_error_key) expect { code }.to raise_validation_error.on_attribute(:skill_sets).of_type(:some_other_key) “`



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/granite/rspec/raise_validation_error.rb', line 16

RSpec::Matchers.define :raise_validation_error do
  chain :on_attribute do |attribute|
    @attribute = attribute
  end

  chain :of_type do |error_type|
    @error_type = error_type
  end

  match do |block|
    block.call
    false
  rescue Granite::Action::ValidationError => e
    @details = e.errors.details
    @details_being_checked = @details[@attribute || :base]
    @result = @details_being_checked&.any? { |x| x[:error] == @error_type }
  end

  description do
    expected = "raise validation error on attribute :#{@attribute || :base}"
    expected << " of type #{@error_type.inspect}" if @error_type
    expected << ", but raised #{@details.inspect}" unless @result
    expected
  end

  failure_message do
    "expected to #{description}"
  end

  failure_message_when_negated do
    "expected not to #{description}"
  end

  supports_block_expectations
end

#satisfy_preconditionsObject

Checks if business action satisfies preconditions in current state.

Modifiers:

  • ‘with_message(message)` (and `with_messages(list, of, messages)`) – only for negated matchers, checks messages of preconditions not satisfied;

  • ‘with_message_of_kind(:message_kind)` (and `with_messages_of_kinds(:list, :of, :messages)`) – only for negated matchers, checks messages of preconditions not satisfied;

  • ‘exactly` (secondary modifier for `with_message`/`with_messages`) – if set, checks if only those messages are set in errors; otherwise those messages should present, but others could too.

Examples:

“‘ruby # assuming subject is business action it { is_expected.to satisfy_preconditions } it { is_expected.not_to satisfy_preconditions.with_message(’Tax form has not been signed’) } it { is_expected.not_to satisfy_preconditions.with_messages(/^Tax form has not been signed by/‘, ’Signature required’) } it { is_expected.not_to satisfy_preconditions.with_message_of_kind(:relevant_portfolio_items_needed) } it { is_expected.not_to satisfy_preconditions.with_messages_of_kinds(:relevant_portfolio_items_needed, :relevant_education_needed) } “‘



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/granite/rspec/satisfy_preconditions.rb', line 25

RSpec::Matchers.define :satisfy_preconditions do
  chain(:with_message) do |message|
    @expected_messages = [message]
  end

  chain(:with_messages) do |*messages|
    @expected_messages = messages.flatten
  end

  chain(:with_message_of_kind) do |kind|
    @expected_kind_of_messages = [kind]
  end

  chain(:with_messages_of_kinds) do |*kinds|
    @expected_kind_of_messages = kinds.flatten
  end

  chain(:exactly) do
    @exactly = true
  end

  match do |object|
    fail '"with_messages" method chain is not supported for positive matcher' if @expected_messages

    object.satisfy_preconditions?
  end

  match_when_negated do |object|
    result = !object.satisfy_preconditions?
    if @expected_messages
      errors = object.errors[:base]

      result &&= @expected_messages.all? { |expected| errors.any? { |error| compare(error, expected) } }

      result &&= errors.none? { |error| @expected_messages.none? { |expected| compare(error, expected) } } if @exactly
    elsif @expected_kind_of_messages
      error_kinds = object.errors.details[:base].map(&:values).flatten
      result &&= (@expected_kind_of_messages - error_kinds).empty?
    end

    result
  end

  failure_message do |object|
    "expected #{object} to satisfy preconditions but got following errors:\n #{object.errors[:base].inspect}"
  end

  failure_message_when_negated do |object|
    message = "expected #{object} not to satisfy preconditions"
    message + if @expected_messages
                expected_messages_error(object, @exactly, @expected_messages)
              elsif @expected_kind_of_messages
                expected_kind_of_messages_error(object, @expected_kind_of_messages)
              else
                ' but preconditions were satisfied'
              end.to_s
  end

  def expected_messages_error(object, exactly, expected_messages, message = '')
    actual_errors = object.errors[:base]
    message += ' exactly' if exactly
    message += " with error messages #{expected_messages}"
    message + " but got following error messages:\n    #{actual_errors.inspect}"
  end

  def expected_kind_of_messages_error(object, expected_kind_of_messages, message = '')
    actual_kind_of_errors = object.errors.details[:base].map(&:keys).flatten
    message += " with error messages of kind #{expected_kind_of_messages}"
    message + " but got following kind of error messages:\n    #{actual_kind_of_errors.inspect}"
  end

  def compare(actual, expected)
    if RSpec::Matchers.is_a_matcher?(expected)
      expected.matches?(actual)
    elsif expected.is_a?(String)
      actual == expected
    else
      actual.match?(expected)
    end
  end
end