Class: Insta::RSpec::Matchers::MatchSnapshot

Inherits:
Object
  • Object
show all
Includes:
RSpec::Matchers::Composable
Defined in:
lib/insta/rspec/matchers.rb,
sig/insta/rspec/matchers.rbs

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = nil, serializer: nil, redact: nil) ⇒ MatchSnapshot

: (String?, ?serializer: Symbol?, ?redact: Hash[String, untyped]?) -> void

Parameters:

  • (String, nil)
  • serializer: (Symbol, nil) (defaults to: nil)
  • redact: (Hash[String, untyped], nil) (defaults to: nil)


14
15
16
17
18
19
# File 'lib/insta/rspec/matchers.rb', line 14

def initialize(name = nil, serializer: nil, redact: nil)
  @name = name
  @serializer = serializer
  @redact = redact
  @failure_message = nil
end

Instance Attribute Details

#failure_messageString? (readonly)

: String?

Returns:

  • (String, nil)


11
12
13
# File 'lib/insta/rspec/matchers.rb', line 11

def failure_message
  @failure_message
end

Instance Method Details

#descriptionString

: () -> String

Returns:

  • (String)


57
58
59
# File 'lib/insta/rspec/matchers.rb', line 57

def description
  @name ? "match snapshot \"#{@name}\"" : "match snapshot"
end

#handle_mismatch(snapshot_file, path, content, metadata, expected, label, caller_line = nil) ⇒ Boolean

: (SnapshotFile, Pathname, String, Snapshot::snapshot_metadata, String, String, String?) -> bool

Parameters:

  • (SnapshotFile)
  • (Pathname)
  • (String)
  • (Snapshot::snapshot_metadata)
  • (String)
  • (String)
  • (String, nil)

Returns:

  • (Boolean)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/insta/rspec/matchers.rb', line 119

def handle_mismatch(snapshot_file, path, content, , expected, label, caller_line = nil)
  result = SnapshotMismatchHandler.handle(snapshot_file, path, content, , expected,
                                          caller_line: caller_line)

  case result
  when :updated, :force_passed
    true
  else
    @failure_message = SnapshotMismatchHandler.failure_message(expected, content, label, path,
                                                               caller_line: caller_line)

    false
  end
end

#handle_new_snapshot(snapshot_file, path, content, metadata) ⇒ Boolean

: (SnapshotFile, Pathname, String, Snapshot::snapshot_metadata) -> bool

Parameters:

  • (SnapshotFile)
  • (Pathname)
  • (String)
  • (Snapshot::snapshot_metadata)

Returns:

  • (Boolean)


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/insta/rspec/matchers.rb', line 77

def handle_new_snapshot(snapshot_file, path, content, )
  if Insta.configuration.resolved_update_mode == :no
    return record_failure("Snapshot file does not exist: #{path}\nRun with INSTA_UPDATE=force to create it.")
  end

  if Insta.configuration.new_snapshot == :review
    pending_path = snapshot_file.pending_path(path)
    snapshot_file.write(pending_path, content, )

    example = ::RSpec.current_example
    caller_line = example&.location
    PendingLocations.add(pending_path.to_s, caller_line) if caller_line

    return true if ENV["INSTA_FORCE_PASS"]

    return record_failure("New snapshot pending review: #{path}\nRun `bundle exec insta review` to accept.")

  end

  snapshot_file.write(path, content, )

  true
end

#handle_type_mismatch(snapshot_file, path, content, metadata, existing, expression, example) ⇒ Boolean

: (SnapshotFile, Pathname, String, Snapshot::snapshot_metadata, Snapshot, String?, untyped) -> bool

Parameters:

  • (SnapshotFile)
  • (Pathname)
  • (String)
  • (Snapshot::snapshot_metadata)
  • (Snapshot)
  • (String, nil)
  • (Object)

Returns:

  • (Boolean)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/insta/rspec/matchers.rb', line 102

def handle_type_mismatch(snapshot_file, path, content, , existing, expression, example)
  expected = SnapshotContent.normalize(existing.content)
  caller_line = example.location
  result = SnapshotMismatchHandler.handle(snapshot_file, path, content, , expected, caller_line: caller_line)

  case result
  when :updated, :force_passed
    true
  else
    record_failure(
      "Snapshot type mismatch: snapshot was #{existing.expression} but got #{expression}\n" \
      "Run `bundle exec insta review` or delete the snapshot file and re-run the test to update it."
    )
  end
end

#matches?(actual) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


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
# File 'lib/insta/rspec/matchers.rb', line 22

def matches?(actual)
  @actual = actual
  expression = actual.class.name

  actual = Redaction::Applicator.apply(actual, @redact) if @redact
  serializer_name = @serializer || Insta.configuration.default_serializer
  serialized = Serializers.serialize(serializer_name, actual)
  content = SnapshotContent.normalize(serialized)

  example = ::RSpec.current_example
  return record_failure("Could not determine current RSpec example") unless example

  test_class = example.example_group.description || "Anonymous"
  test_method = example.description || "unknown"

  snapshot_file = resolve_snapshot_file(example, test_class, test_method)
  path = @name ? snapshot_file.named_path(@name) : snapshot_file.path_for

   = { "source" => "#{test_class} #{test_method}", "expression" => expression }
  existing = snapshot_file.read(path)

  return handle_new_snapshot(snapshot_file, path, content, ) unless existing

  if existing.expression && existing.expression != expression
    return handle_type_mismatch(snapshot_file, path, content, , existing, expression, example)
  end

  expected = SnapshotContent.normalize(existing.content)
  return true if content == expected

  caller_line = example.location
  handle_mismatch(snapshot_file, path, content, , expected, "#{test_class} #{test_method}", caller_line)
end

#record_failure(msg) ⇒ false

: (String) -> false

Parameters:

  • (String)

Returns:

  • (false)


135
136
137
138
139
# File 'lib/insta/rspec/matchers.rb', line 135

def record_failure(msg)
  @failure_message = msg

  false
end

#resolve_snapshot_file(example, test_class, test_method) ⇒ SnapshotFile

: (untyped, String, String) -> SnapshotFile

Parameters:

  • (Object)
  • (String)
  • (String)

Returns:



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/insta/rspec/matchers.rb', line 64

def resolve_snapshot_file(example, test_class, test_method)
  if @name
    SnapshotFile.new(Insta.configuration.snapshot_path, test_class, test_method)
  else
    example.[:_insta_snapshot_file] ||= SnapshotFile.new(
      Insta.configuration.snapshot_path,
      test_class,
      test_method
    )
  end
end