pact 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/.travis.yml +1 -1
  2. data/CHANGELOG.md +14 -0
  3. data/Gemfile.lock +5 -5
  4. data/README.md +25 -29
  5. data/documentation/README.md +9 -7
  6. data/lib/pact/configuration.rb +83 -12
  7. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +5 -1
  8. data/lib/pact/consumer/spec_hooks.rb +7 -4
  9. data/lib/pact/consumer/world.rb +12 -0
  10. data/lib/pact/consumer_contract/headers.rb +51 -0
  11. data/lib/pact/consumer_contract/request.rb +6 -1
  12. data/lib/pact/provider/configuration/service_provider_dsl.rb +6 -1
  13. data/lib/pact/provider/matchers/messages.rb +2 -2
  14. data/lib/pact/provider/rspec.rb +7 -1
  15. data/lib/pact/provider/rspec/backtrace_formatter.rb +30 -6
  16. data/lib/pact/provider/rspec/matchers.rb +9 -6
  17. data/lib/pact/shared/json_differ.rb +15 -0
  18. data/lib/pact/shared/request.rb +11 -2
  19. data/lib/pact/shared/text_differ.rb +14 -0
  20. data/lib/pact/version.rb +1 -1
  21. data/spec/lib/pact/configuration_spec.rb +127 -5
  22. data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +8 -5
  23. data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
  24. data/spec/lib/pact/consumer_contract/request_spec.rb +9 -0
  25. data/spec/lib/pact/matchers/matchers_spec.rb +35 -0
  26. data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +16 -0
  27. data/spec/lib/pact/provider/matchers/messages_spec.rb +5 -4
  28. data/spec/lib/pact/provider/rspec_spec.rb +15 -11
  29. data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
  30. data/spec/lib/pact/shared/request_spec.rb +25 -1
  31. data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
  32. data/spec/support/pact_helper.rb +2 -0
  33. data/spec/support/test_app_with_right_content_type_differ.json +23 -0
  34. data/tasks/pact-test.rake +6 -0
  35. metadata +72 -30
  36. checksums.yaml +0 -7
  37. data/documentation/Testing with pact.png +0 -0
  38. data/documentation/best-practices.md +0 -33
  39. data/documentation/development-workflow.md +0 -22
  40. data/documentation/faq.md +0 -81
  41. data/documentation/provider-states.md +0 -178
  42. data/documentation/raq.md +0 -39
  43. data/documentation/terminology.md +0 -25
  44. data/documentation/troubleshooting.md +0 -4
  45. data/documentation/verifying-pacts.md +0 -106
data/.travis.yml CHANGED
@@ -5,4 +5,4 @@ rvm:
5
5
  - 2.1.1
6
6
  - jruby-19mode
7
7
  - jruby-1.7.11
8
- - jruby-head
8
+ - jruby-1.7.12
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@ Do this to generate your change history
2
2
 
3
3
  git log --pretty=format:' * %h - %s (%an, %ad)'
4
4
 
5
+ ### 1.3.1 (11 August 2014)
6
+
7
+ * 3432259 - Fixed 'pact:verify broken with rspec-core 3.0.3' https://github.com/realestate-com-au/pact/issues/44 (bethesque, Mon Aug 11 10:14:42 2014 +1000)
8
+ * e2e8eff - Deleted documentation that has been moved to the wiki (bethesque, Thu Jul 24 15:20:07 2014 +1000)
9
+ * bcc3143 - Fixing bug 'Method case should not matter when matching requests' https://github.com/realestate-com-au/pact/issues/41 (bethesque, Tue Jul 22 16:51:48 2014 +1000)
10
+ * d4bfab9 - Adding ability to configure DiffFormatter based on content-type (bethesque, Mon Jun 23 21:22:47 2014 +1000)
11
+ * eb330ea - Ensured content-type header works in a case insensitive way when looking up the right differ (bethesque, Mon Jun 23 17:23:04 2014 +1000)
12
+ * 2733e8e - Made header matching case insensitive for requests. Fixing issue https://github.com/realestate-com-au/pact/issues/20 (bethesque, Mon May 26 19:15:48 2014 +1000)
13
+ * 2b8355d - Added nicer error message for scenario when a service provider app has not been configured, and there is no config.ru (bethesque, Mon Jun 23 09:42:18 2014 +1000)
14
+ * 1e774bb - Defaulting to TextDiffer if response has no content-type (bethesque, Sat Jun 21 10:34:44 2014 +1000)
15
+ * 863b093 - Added support for documents without content types (bethesque, Sat Jun 21 10:32:08 2014 +1000)
16
+ * b21900b - Enabling differs to be configured based on Content-Type (bethesque, Sat Jun 21 10:21:37 2014 +1000)
17
+ * 527b5d5 - Modified after hook to only write pacts when one or more 'pact => true' examples have run (bethesque, Wed Jun 18 15:15:55 2014 +1000)
18
+
5
19
  ### 1.3.0 (18 June 2014)
6
20
 
7
21
  * ea79190 - Modifying (cough*monkeypatching*cough) RSpec::Core::BacktraceFormatter as RSpec3 has some hardcoded exclusion patterns that result in *all* the backtrace lines being shown when pact:verify fails. (bethesque, Wed Jun 18 13:02:38 2014 +1000)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pact (1.3.0)
4
+ pact (1.3.1)
5
5
  awesome_print (~> 1.1)
6
6
  find_a_port (~> 1.0.1)
7
7
  json
@@ -50,14 +50,14 @@ GEM
50
50
  rspec-core (~> 3.0.0)
51
51
  rspec-expectations (~> 3.0.0)
52
52
  rspec-mocks (~> 3.0.0)
53
- rspec-core (3.0.1)
53
+ rspec-core (3.0.3)
54
54
  rspec-support (~> 3.0.0)
55
- rspec-expectations (3.0.1)
55
+ rspec-expectations (3.0.3)
56
56
  diff-lcs (>= 1.2.0, < 2.0)
57
57
  rspec-support (~> 3.0.0)
58
- rspec-mocks (3.0.1)
58
+ rspec-mocks (3.0.3)
59
59
  rspec-support (~> 3.0.0)
60
- rspec-support (3.0.0)
60
+ rspec-support (3.0.3)
61
61
  safe_yaml (1.0.3)
62
62
  slop (3.5.0)
63
63
  term-ansicolor (1.3.0)
data/README.md CHANGED
@@ -14,6 +14,12 @@ Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestat
14
14
 
15
15
  Pact is most valuable for designing and testing integrations where you (or your team/organisation/partner organisation) control the development of both the consumer and the provider. It is fantastic tool for intra-organsation microservices.
16
16
 
17
+ ## What is it not good for?
18
+
19
+ * Performance and load testing.
20
+ * Functional testing of the provider - that is what the provider's own tests should do. Pact is about checking the contents and format of requests and responses.
21
+ * Situations where you cannot load data into the provider without using the API that you're actually testing.
22
+
17
23
  ## Features
18
24
 
19
25
  * A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
@@ -27,7 +33,7 @@ Pact is most valuable for designing and testing integrations where you (or your
27
33
  ## How does it work?
28
34
 
29
35
  1. In the specs for the provider facing code in the consumer project, expectations are set up on a mock service provider.
30
- 1. When the specs are run, the requests, and their expected responses, are written to a "pact" file.
36
+ 1. When the specs are run, the mock service returns the expected responses. The requests, and their expected responses, are then written to a "pact" file.
31
37
  1. The requests in the pact file are later replayed against the provider, and the actual responses are checked to make sure they match the expected responses.
32
38
 
33
39
  ## Why is developing and testing with Pact better than using traditional system integration tests?
@@ -37,6 +43,7 @@ Pact is most valuable for designing and testing integrations where you (or your
37
43
  * Causes of failure are easier to identify as only one component is being tested at a time.
38
44
  * Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
39
45
  * No separate integration environment required for automated integration tests - pact tests run in standalone CI builds.
46
+ * Integration flows that would traditionally require running multiple services at the same time can be broken down and each integration point tested separately.
40
47
 
41
48
  ## Contact
42
49
 
@@ -180,7 +187,7 @@ require 'pact/tasks'
180
187
 
181
188
  Create a `pact_helper.rb` in your service provider project. The recommended place is `spec/service_consumers/pact_helper.rb`.
182
189
 
183
- See [Verifying Pacts](documentation/verifying-pacts.md) and the [Provider](documentation/configuration.md#provider) section of the Configuration documentation for more information.
190
+ See [Verifying Pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts) and the [Provider](documentation/configuration.md#provider) section of the Configuration documentation for more information.
184
191
 
185
192
  ```ruby
186
193
  # In specs/service_consumers/pact_helper.rb
@@ -220,29 +227,8 @@ Yay! Your provider now honours the pact it has with your consumer. You can now h
220
227
 
221
228
  ### Using provider states
222
229
 
223
- Provider states allow you to set up data on the provider before the interaction is run, so that it can make a response that matches what the consumer expects. It also allows the consumer to make the same request with different expected responses.
224
-
225
- Read more about provider states [here](/documentation/provider-states.md).
226
-
227
- ### Verifying pacts
230
+ Each interaction in a pact is verified in isolation, with no context maintained from the previous interactions. So how do you test a request that requires data to already exist on the provider? Read about provider states [here](https://github.com/realestate-com-au/pact/wiki/Provider-states).
228
231
 
229
- You can verify a pact at an arbitrary local or remote URL
230
-
231
- $ rake pact:verify:at[../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json]
232
- $ rake pact:verify:at[http://build-box/MyConsumerBuild/latestSuccessful/artifacts/my_consumer-my_provider.json]
233
-
234
- To make a shortcut task for pact at an arbitrary URL, add the following to your Rakefile. The pact.uri may be a local file system path or a remote URL.
235
-
236
- ```ruby
237
- # In Rakefile or /tasks/pact.rake
238
-
239
- # This creates a rake task that can be executed by running
240
- # $ rake pact:verify:dev
241
-
242
- Pact::VerificationTask.new(:dev) do | pact |
243
- pact.uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
244
- end
245
- ```
246
232
 
247
233
  ## Configuration
248
234
 
@@ -250,15 +236,20 @@ See the [Configuration](/documentation/configuration.md) section of the document
250
236
 
251
237
  ## Pact best practices
252
238
 
253
- As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](/documentation/best-practices.md) section of the documentation to make sure you're not Pacting it Wrong.
239
+ As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices) section of the documentation to make sure you're not Pacting it Wrong.
254
240
 
255
241
  ## Docs
256
242
 
257
243
  * [Example](example)
258
- * [Frequently Asked Questions](documentation/faq.md)
259
- * [Rarely Asked Questions](documentation/raq.md)
260
- * [Terminology](documentation/terminology.md)
261
- * [Configuration](/documentation/configuration.md)
244
+ * [Configuration](documentation/configuration.md)
245
+ * [Terminology](https://github.com/realestate-com-au/pact/wiki/Terminology)
246
+ * [Provider States](https://github.com/realestate-com-au/pact/wiki/Provider-states)
247
+ * [Verifying pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts)
248
+ * [Frequently asked questions](https://github.com/realestate-com-au/pact/wiki/FAQ)
249
+ * [Rarely asked questions](https://github.com/realestate-com-au/pact/wiki/RAQ)
250
+ * [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices)
251
+ * [Troubleshooting](https://github.com/realestate-com-au/pact/wiki/Troubleshooting)
252
+ * [Testing with pact diagram](https://github.com/realestate-com-au/pact/wiki/Testing with pact.png)
262
253
 
263
254
  ## Related libraries
264
255
 
@@ -270,6 +261,8 @@ As in all things, there are good ways to implement Pacts, and there are not so g
270
261
 
271
262
  [Pact JVM](https://github.com/DiUS/pact-jvm) - A Pact implementation for the JVM (Java and Scala). It generates pact files that are compatible with the Ruby implementation.
272
263
 
264
+ [Pact .NET](https://github.com/SEEK-Jobs/pact-net) - A Pact implementation for .NET.
265
+
273
266
  [Shokkenki](https://github.com/brentsnook/shokkenki) - Another Consumer Driven Contract gem written by one of Pact's original authors, Brent Snook. Shokkenki allows matchers to be composed using jsonpath expressions and allows auto-generation of mock response values based on regular expressions.
274
267
 
275
268
  ## Links
@@ -301,3 +294,6 @@ Long term:
301
294
  3. Commit your changes (`git commit -am 'Add some feature'`)
302
295
  4. Push to the branch (`git push origin my-new-feature`)
303
296
  5. Create new Pull Request
297
+
298
+ If you would like to implement pact in another language, please check out the [Pact specification](https://github.com/bethesque/pact-specification) and have a chat to one of us on the [pact-dev Google group](https://groups.google.com/forum/#!forum/pact-dev). The vision is to have a compatible pact implementation in all the commonly used languages, your help would be greatly appreciated!
299
+
@@ -1,11 +1,13 @@
1
1
  ### Pact Documentation
2
2
 
3
3
  * Step by step instructions for getting started with pacts can be found in the project [README.md](/README.md#usage)
4
- * [Terminology](terminology.md)
4
+ * [Terminology](https://github.com/realestate-com-au/pact/wiki/Terminology)
5
5
  * [Configuration](configuration.md)
6
- * [Provider States](provider-states.md)
7
- * [Frequently asked questions](faq.md)
8
- * [Rarely asked questions](raq.md)
9
- * [Best practices](best-practices.md)
10
- * [Troubleshooting](troubleshooting.md)
11
- * [Testing with pact diagram](Testing with pact.png)
6
+ * [Provider States](https://github.com/realestate-com-au/pact/wiki/Provider-states)
7
+ * [Verifying pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts)
8
+ * [Frequently asked questions](https://github.com/realestate-com-au/pact/wiki/FAQ)
9
+ * [Rarely asked questions](https://github.com/realestate-com-au/pact/wiki/RAQ)
10
+ * [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices)
11
+ * [Troubleshooting](https://github.com/realestate-com-au/pact/wiki/Troubleshooting)
12
+ * [Testing with pact diagram](https://github.com/realestate-com-au/pact/wiki/Testing with pact.png)
13
+ * [Development workflow](https://github.com/realestate-com-au/pact/wiki/Development-workflow)
@@ -4,6 +4,8 @@ require 'pact/doc/markdown/generator'
4
4
  require 'pact/matchers/unix_diff_formatter'
5
5
  require 'pact/matchers/embedded_diff_formatter'
6
6
  require 'pact/matchers/list_diff_formatter'
7
+ require 'pact/shared/json_differ'
8
+ require 'pact/shared/text_differ'
7
9
 
8
10
  module Pact
9
11
 
@@ -17,6 +19,27 @@ module Pact
17
19
  :list => Pact::Matchers::ListDiffFormatter
18
20
  }
19
21
 
22
+
23
+ class NilMatcher
24
+ def self.=~ other
25
+ other == nil ? 0 : nil
26
+ end
27
+ end
28
+
29
+ DIFF_FORMATTER_REGISTRATIONS = [
30
+ [/.*/, Pact::Matchers::UnixDiffFormatter],
31
+ [NilMatcher, Pact::Matchers::UnixDiffFormatter]
32
+ ]
33
+
34
+ DIFFERS = [
35
+ [/json/, Pact::JsonDiffer],
36
+ [NilMatcher, Pact::TextDiffer],
37
+ [/.*/, Pact::TextDiffer]
38
+ ]
39
+
40
+
41
+ DEFAULT_DIFFER = Pact::TextDiffer
42
+
20
43
  attr_accessor :pact_dir
21
44
  attr_accessor :log_dir
22
45
  attr_accessor :doc_dir
@@ -41,6 +64,11 @@ module Pact
41
64
  c
42
65
  end
43
66
 
67
+ def initialize
68
+ @differ_registrations = []
69
+ @diff_formatter_registrations = []
70
+ end
71
+
44
72
  def logger
45
73
  @logger ||= create_logger
46
74
  end
@@ -61,20 +89,29 @@ module Pact
61
89
  @doc_generators ||= []
62
90
  end
63
91
 
64
- def diff_formatter
65
- @diff_formatter ||= DIFF_FORMATTERS[:unix]
92
+ # Should this be deprecated in favour of register_diff_formatter???
93
+ def diff_formatter= diff_formatter
94
+ register_diff_formatter /.*/, diff_formatter
95
+ register_diff_formatter nil, diff_formatter
66
96
  end
67
97
 
68
- def diff_formatter= diff_formatter
69
- @diff_formatter = begin
70
- if DIFF_FORMATTERS[diff_formatter]
71
- DIFF_FORMATTERS[diff_formatter]
72
- elsif diff_formatter.respond_to?(:call)
73
- diff_formatter
74
- else
75
- raise "Pact.configuration.diff_formatter needs to respond to call, or be in the preconfigured list: #{DIFF_FORMATTERS.keys}"
76
- end
77
- end
98
+ def register_diff_formatter content_type, diff_formatter
99
+ key = content_type_regexp_for content_type
100
+ @diff_formatter_registrations << [key, diff_formatter_for(diff_formatter)]
101
+ end
102
+
103
+ def diff_formatter_for_content_type content_type
104
+ diff_formatter_registrations.find{ | registration | registration.first =~ content_type }.last
105
+ end
106
+
107
+ def register_body_differ content_type, differ
108
+ key = content_type_regexp_for content_type
109
+ validate_differ differ
110
+ @differ_registrations << [key, differ]
111
+ end
112
+
113
+ def body_differ_for_content_type content_type
114
+ differ_registrations.find{ | registration | registration.first =~ content_type }.last
78
115
  end
79
116
 
80
117
  def log_path
@@ -91,6 +128,40 @@ module Pact
91
128
 
92
129
  private
93
130
 
131
+ def diff_formatter_for input
132
+ if DIFF_FORMATTERS[input]
133
+ DIFF_FORMATTERS[input]
134
+ elsif input.respond_to?(:call)
135
+ input
136
+ else
137
+ raise "Pact diff_formatter needs to respond to call, or be in the preconfigured list: #{DIFF_FORMATTERS.keys}"
138
+ end
139
+ end
140
+
141
+ def validate_differ differ
142
+ if !differ.respond_to?(:call)
143
+ raise "Pact.configuration.register_body_differ expects a differ that is a lamda or a class/object that responds to call."
144
+ end
145
+ end
146
+
147
+ def content_type_regexp_for content_type
148
+ case content_type
149
+ when String then Regexp.new(/^#{Regexp.escape(content_type)}$/)
150
+ when Regexp then content_type
151
+ when nil then NilMatcher
152
+ else
153
+ raise "Invalid content type used to register a differ (#{content_type.inspect}). Please use a Regexp or a String."
154
+ end
155
+ end
156
+
157
+ def differ_registrations
158
+ @differ_registrations + DIFFERS
159
+ end
160
+
161
+ def diff_formatter_registrations
162
+ @diff_formatter_registrations + DIFF_FORMATTER_REGISTRATIONS
163
+ end
164
+
94
165
  def self.default_log_dir
95
166
  File.expand_path("./log")
96
167
  end
@@ -56,10 +56,14 @@ module Pact
56
56
  def to_s
57
57
  [
58
58
  "Diff with interaction: #{candidate_interaction.description_with_provider_state_quoted}",
59
- Pact.configuration.diff_formatter.call(diff, {colour: false})
59
+ diff_formatter.call(diff, {colour: false})
60
60
  ].join("\n")
61
61
  end
62
62
 
63
+ def diff_formatter
64
+ Pact.configuration.diff_formatter_for_content_type(candidate_interaction.request.content_type)
65
+ end
66
+
63
67
  def diff
64
68
  @diff ||= candidate_interaction.request.difference(actual_request)
65
69
  end
@@ -11,6 +11,7 @@ module Pact
11
11
  end
12
12
 
13
13
  def before_each example_description
14
+ Pact.consumer_world.register_pact_example_ran
14
15
  Pact.configuration.logger.info "Clearing all expectations"
15
16
  Pact::Consumer::AppManager.instance.ports_of_mock_services.each do | port |
16
17
  Pact::Consumer::MockServiceClient.clear_interactions port, example_description
@@ -25,10 +26,12 @@ module Pact
25
26
  end
26
27
 
27
28
  def after_suite
28
- Pact.consumer_world.consumer_contract_builders.each { | c | c.write_pact }
29
- Pact::Doc::Generate.call
30
- Pact::Consumer::AppManager.instance.kill_all
31
- Pact::Consumer::AppManager.instance.clear_all
29
+ if Pact.consumer_world.any_pact_examples_ran?
30
+ Pact.consumer_world.consumer_contract_builders.each { | c | c.write_pact }
31
+ Pact::Doc::Generate.call
32
+ Pact::Consumer::AppManager.instance.kill_all
33
+ Pact::Consumer::AppManager.instance.clear_all
34
+ end
32
35
  end
33
36
  end
34
37
  end
@@ -12,6 +12,10 @@ module Pact
12
12
  module Consumer
13
13
  class World
14
14
 
15
+ def initialize
16
+ @any_pact_examples_ran = false
17
+ end
18
+
15
19
  def consumer_contract_builders
16
20
  @consumer_contract_builders ||= []
17
21
  end
@@ -20,6 +24,14 @@ module Pact
20
24
  consumer_contract_builders << consumer_contract_builder
21
25
  end
22
26
 
27
+ def register_pact_example_ran
28
+ @any_pact_examples_ran = true
29
+ end
30
+
31
+ def any_pact_examples_ran?
32
+ @any_pact_examples_ran
33
+ end
34
+
23
35
  end
24
36
  end
25
37
  end
@@ -0,0 +1,51 @@
1
+ module Pact
2
+
3
+ class DuplicateHeaderError < StandardError; end
4
+ class InvalidHeaderNameTypeError < StandardError; end
5
+
6
+ class Headers < Hash
7
+
8
+ def initialize hash = {}
9
+ hash.each_pair do | key, value |
10
+ check_for_invalid key
11
+ self[find_matching_key(key)] = value
12
+ end
13
+ self.freeze
14
+ end
15
+
16
+ def [] key
17
+ super(find_matching_key(key))
18
+ end
19
+
20
+ def fetch *args, &block
21
+ args[0] = find_matching_key(args[0]) if args.first
22
+ super(*args, &block)
23
+ end
24
+
25
+ def key? key
26
+ super(find_matching_key(key))
27
+ end
28
+
29
+ alias_method :has_key?, :key?
30
+ alias_method :include?, :key?
31
+
32
+ private
33
+
34
+ def find_matching_key key
35
+ key = key.to_s
36
+ match = keys.find { |k| k.downcase == key.downcase }
37
+ match.nil? ? key : match
38
+ end
39
+
40
+ def check_for_invalid key
41
+ unless (String === key || Symbol === key)
42
+ raise InvalidHeaderNameTypeError.new "Header name (#{key}) must be a String or a Symbol."
43
+ end
44
+ if key? key
45
+ raise DuplicateHeaderError.new "Duplicate header found (#{find_matching_key(key)} and #{key}. Please use a comma separated single value when multiple headers with the same name are required."
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -60,8 +60,13 @@ module Pact
60
60
  end
61
61
 
62
62
  def body_difference(actual_body)
63
- diff({:body => body}, {body: actual_body}, allow_unexpected_keys: runtime_options[:allow_unexpected_keys_in_body])
63
+ body_differ.call({:body => body}, {body: actual_body}, allow_unexpected_keys: runtime_options[:allow_unexpected_keys_in_body])
64
64
  end
65
+
66
+ def body_differ
67
+ Pact.configuration.body_differ_for_content_type content_type
68
+ end
69
+
65
70
  end
66
71
 
67
72
  end