Welcome to mirror list, hosted at ThFree Co, Russian Federation.

next_found_instance_of.rb « helpers « support « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f53798c18569aea07f1dc6517130a84488c90038 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
51
52
53
54
55
56
57
58
59
60
61
# frozen_string_literal: true

module NextFoundInstanceOf
  ERROR_MESSAGE = 'NextFoundInstanceOf mock helpers can only be used with ActiveRecord targets'
  HELPER_METHOD_PATTERN = /(?:allow|expect)_next_found_(?<number>\d+)_instances_of/

  def method_missing(method_name, ...)
    return super unless match_data = method_name.match(HELPER_METHOD_PATTERN)

    helper_method = method_name.to_s.sub("_#{match_data[:number]}", '')

    public_send(helper_method, *args, match_data[:number].to_i, &block)
  end

  def expect_next_found_instance_of(klass, &block)
    expect_next_found_instances_of(klass, nil, &block)
  end

  def expect_next_found_instances_of(klass, number)
    check_if_active_record!(klass)

    stub_allocate(expect(klass), klass, number) do |expectation|
      yield(expectation)
    end
  end

  def allow_next_found_instance_of(klass, &block)
    allow_next_found_instances_of(klass, nil, &block)
  end

  def allow_next_found_instances_of(klass, number)
    check_if_active_record!(klass)

    stub_allocate(allow(klass), klass, number) do |allowance|
      yield(allowance)
    end
  end

  private

  def check_if_active_record!(klass)
    raise ArgumentError, ERROR_MESSAGE unless klass < ActiveRecord::Base
  end

  def stub_allocate(target, klass, number)
    stub = receive(:allocate)
    stub.exactly(number).times if number

    target.to stub.and_wrap_original do |method|
      method.call.tap do |allocation|
        # ActiveRecord::Core.allocate returns a frozen object:
        # https://github.com/rails/rails/blob/291a3d2ef29a3842d1156ada7526f4ee60dd2b59/activerecord/lib/active_record/core.rb#L620
        # It's unexpected behavior and probably a bug in Rails
        # Let's work it around by setting the attributes to default to unfreeze the object for now
        allocation.instance_variable_set(:@attributes, klass._default_attributes)

        yield(allocation)
      end
    end
  end
end