pact-support 1.4.0 → 1.7.0

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -0
  3. data/lib/pact/configuration.rb +4 -0
  4. data/lib/pact/consumer_contract/consumer_contract.rb +19 -8
  5. data/lib/pact/consumer_contract/http_consumer_contract_parser.rb +37 -0
  6. data/lib/pact/consumer_contract/interaction.rb +52 -57
  7. data/lib/pact/consumer_contract/interaction_parser.rb +23 -0
  8. data/lib/pact/consumer_contract/interaction_v2_parser.rb +28 -0
  9. data/lib/pact/consumer_contract/interaction_v3_parser.rb +61 -0
  10. data/lib/pact/consumer_contract/pact_file.rb +24 -24
  11. data/lib/pact/consumer_contract/query_hash.rb +2 -0
  12. data/lib/pact/consumer_contract/query_string.rb +2 -2
  13. data/lib/pact/consumer_contract/request.rb +1 -5
  14. data/lib/pact/consumer_contract/string_with_matching_rules.rb +17 -0
  15. data/lib/pact/matchers/multipart_form_diff_formatter.rb +41 -0
  16. data/lib/pact/matching_rules/merge.rb +30 -14
  17. data/lib/pact/matching_rules/v3/extract.rb +94 -0
  18. data/lib/pact/matching_rules/v3/merge.rb +128 -0
  19. data/lib/pact/matching_rules.rb +19 -6
  20. data/lib/pact/reification.rb +6 -3
  21. data/lib/pact/shared/multipart_form_differ.rb +14 -0
  22. data/lib/pact/specification_version.rb +18 -0
  23. data/lib/pact/support/version.rb +1 -1
  24. data/script/release.sh +1 -1
  25. data/spec/fixtures/multipart-form-diff.txt +9 -0
  26. data/spec/fixtures/not-a-pact.json +3 -0
  27. data/spec/fixtures/pact-http-v2.json +36 -0
  28. data/spec/fixtures/pact-http-v3.json +36 -0
  29. data/spec/integration/matching_rules_extract_and_merge_spec.rb +41 -4
  30. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +54 -31
  31. data/spec/lib/pact/consumer_contract/http_consumer_contract_parser_spec.rb +25 -0
  32. data/spec/lib/pact/consumer_contract/interaction_parser_spec.rb +62 -0
  33. data/spec/lib/pact/consumer_contract/interaction_spec.rb +0 -23
  34. data/spec/lib/pact/consumer_contract/pact_file_spec.rb +9 -0
  35. data/spec/lib/pact/consumer_contract/query_hash_spec.rb +23 -0
  36. data/spec/lib/pact/matchers/multipart_form_diff_formatter_spec.rb +36 -0
  37. data/spec/lib/pact/matching_rules/merge_spec.rb +20 -7
  38. data/spec/lib/pact/matching_rules/v3/extract_spec.rb +238 -0
  39. data/spec/lib/pact/matching_rules/v3/merge_spec.rb +386 -0
  40. data/spec/lib/pact/matching_rules_spec.rb +82 -0
  41. data/spec/lib/pact/reification_spec.rb +18 -5
  42. data/spec/lib/pact/shared/multipart_form_differ_spec.rb +39 -0
  43. data/tasks/spec.rake +0 -1
  44. metadata +35 -3
@@ -3,50 +3,73 @@ require 'pact/consumer_contract'
3
3
 
4
4
  module Pact
5
5
  describe ConsumerContract do
6
+ describe "from_uri" do
7
+ context "when the URL does not point to a valid pact" do
8
+ subject { ConsumerContract.from_uri('spec/fixtures/not-a-pact.json') }
9
+
10
+ it "raises a helpful error" do
11
+ expect { subject }.to raise_error UnrecognizePactFormatError, /Please check that spec/
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "from_hash" do
17
+ context "when the hash is not a valid pact" do
18
+ subject { ConsumerContract.from_hash({'foo' => 'bar'}) }
19
+
20
+ it "raises a helpful error" do
21
+ expect { subject }.to raise_error UnrecognizePactFormatError, 'This document does not use a recognised Pact format: {"foo"=>"bar"}'
22
+ end
23
+ end
24
+ end
6
25
 
7
26
  describe ".from_json" do
27
+
8
28
  let(:loaded_pact) { ConsumerContract.from_json(string) }
9
- context "when the top level object is a ConsumerContract" do
10
- let(:string) { '{"interactions":[{"request": {"path":"/path", "method" : "get"}, "response": {"status" : 200}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"} }' }
11
29
 
12
- it "should create a Pact" do
13
- expect(loaded_pact).to be_instance_of ConsumerContract
14
- end
30
+ context "with an HTTP contract" do
31
+ context "when the top level object is a ConsumerContract" do
32
+ let(:string) { '{"interactions":[{"request": {"path":"/path", "method" : "get"}, "response": {"status" : 200}}], "consumer": {"name" : "Bob"} , "provider": {"name" : "Mary"} }' }
15
33
 
16
- it "should have interactions" do
17
- expect(loaded_pact.interactions).to be_instance_of Array
18
- end
34
+ it "should create a Pact" do
35
+ expect(loaded_pact).to be_instance_of ConsumerContract
36
+ end
19
37
 
20
- it "should have a consumer" do
21
- expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
22
- end
38
+ it "should have interactions" do
39
+ expect(loaded_pact.interactions).to be_instance_of Array
40
+ end
23
41
 
24
- it "should have a provider" do
25
- expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
26
- end
27
- end
42
+ it "should have a consumer" do
43
+ expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
44
+ end
28
45
 
29
- context "with old 'producer' key" do
30
- let(:string) { File.read('./spec/support/a_consumer-a_producer.json')}
31
- it "should create a Pact" do
32
- expect(loaded_pact).to be_instance_of ConsumerContract
46
+ it "should have a provider" do
47
+ expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
48
+ end
33
49
  end
34
50
 
35
- it "should have interactions" do
36
- expect(loaded_pact.interactions).to be_instance_of Array
37
- end
51
+ context "with old 'producer' key" do
52
+ let(:string) { File.read('./spec/support/a_consumer-a_producer.json')}
53
+ it "should create a Pact" do
54
+ expect(loaded_pact).to be_instance_of ConsumerContract
55
+ end
38
56
 
39
- it "should have a consumer" do
40
- expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
41
- end
57
+ it "should have interactions" do
58
+ expect(loaded_pact.interactions).to be_instance_of Array
59
+ end
42
60
 
43
- it "should have a provider" do
44
- expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
45
- expect(loaded_pact.provider.name).to eq "an old producer"
46
- end
61
+ it "should have a consumer" do
62
+ expect(loaded_pact.consumer).to be_instance_of Pact::ServiceConsumer
63
+ end
47
64
 
48
- it "should have a provider_state" do
49
- expect(loaded_pact.interactions.first.provider_state).to eq 'state one'
65
+ it "should have a provider" do
66
+ expect(loaded_pact.provider).to be_instance_of Pact::ServiceProvider
67
+ expect(loaded_pact.provider.name).to eq "an old producer"
68
+ end
69
+
70
+ it "should have a provider_state" do
71
+ expect(loaded_pact.interactions.first.provider_state).to eq 'state one'
72
+ end
50
73
  end
51
74
  end
52
75
  end
@@ -0,0 +1,25 @@
1
+ require 'pact/consumer_contract/http_consumer_contract_parser'
2
+
3
+ module Pact
4
+ describe HttpConsumerContractParser do
5
+ describe "#call integration test" do
6
+ subject { HttpConsumerContractParser.new.call(pact_hash) }
7
+
8
+ context "with a v2 pact" do
9
+ let(:pact_hash) { load_json_fixture('pact-http-v2.json') }
10
+
11
+ it "correctly parses the pact" do
12
+ expect(subject.interactions.first.response.headers['Content-Type']).to be_a(Pact::Term)
13
+ end
14
+ end
15
+
16
+ context "with a v3 pact" do
17
+ let(:pact_hash) { load_json_fixture('pact-http-v3.json') }
18
+
19
+ it "correctly parses the pact" do
20
+ expect(subject.interactions.first.response.body['foo']).to be_a(Pact::SomethingLike)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ require 'pact/consumer_contract/interaction_parser'
2
+
3
+ module Pact
4
+ describe InteractionParser do
5
+ describe ".call" do
6
+
7
+ let(:request) { {method: 'get', path: 'path'} }
8
+ let(:response) { {} }
9
+
10
+ context "when providerState has been used instead of provider_state" do
11
+
12
+ subject { InteractionParser.call('response' => response, 'request' => request, 'providerState' => 'some state') }
13
+
14
+ it "recognises the provider state" do
15
+ expect(subject.provider_state).to eq 'some state'
16
+ end
17
+ end
18
+
19
+ context "when there are matching rules" do
20
+ let(:hash) { load_json_fixture 'interaction-with-matching-rules.json' }
21
+
22
+ subject { InteractionParser.call(hash, pact_specification_version: Pact::SpecificationVersion.new("2")) }
23
+
24
+ it "merges the rules with the example for the request" do
25
+ expect(subject.request.body['name']).to be_instance_of(Pact::Term)
26
+ end
27
+
28
+ it "merges the rules with the example for the response" do
29
+ expect(subject.response.body['_links']['self']['href']).to be_instance_of(Pact::Term)
30
+ end
31
+ end
32
+
33
+ context "when the request body is a String" do
34
+ let(:hash) { { 'request' => request, 'response' => response } }
35
+ subject { InteractionParser.call(hash, pact_specification_version: Pact::SpecificationVersion.new("3")) }
36
+
37
+ let(:request) { { 'method' => 'get', 'path' => 'path' , 'body' => "<xml></xml>", 'matchingRules' => {"body" => {"foo" => "bar"} } } }
38
+
39
+ it "returns an interaction with an StringWithMatchingRules in the request" do
40
+ expect(subject.request.body).to be_a(Pact::StringWithMatchingRules)
41
+ expect(subject.request.body).to eq "<xml></xml>"
42
+ expect(subject.request.body.matching_rules).to eq "foo" => "bar"
43
+ expect(subject.request.body.pact_specification_version).to eq Pact::SpecificationVersion.new("3")
44
+ end
45
+ end
46
+
47
+ context "when the response body is a String" do
48
+ let(:hash) { { 'request' => request, 'response' => response } }
49
+ subject { InteractionParser.call(hash, pact_specification_version: Pact::SpecificationVersion.new("3")) }
50
+
51
+ let(:response) { { 'status' => '200', 'body' => "<xml></xml>", 'matchingRules' => {"body" => {"foo" => "bar"} } } }
52
+
53
+ it "returns an interaction with an StringWithMatchingRules in the response" do
54
+ expect(subject.response.body).to be_a(Pact::StringWithMatchingRules)
55
+ expect(subject.response.body).to eq "<xml></xml>"
56
+ expect(subject.response.body.matching_rules).to eq "foo" => "bar"
57
+ expect(subject.response.body.pact_specification_version).to eq Pact::SpecificationVersion.new("3")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -52,30 +52,7 @@ module Pact
52
52
  end
53
53
  end
54
54
 
55
- describe "from_hash" do
56
- context "when providerState has been used instead of provider_state" do
57
55
 
58
- subject { Interaction.from_hash('response' => response, 'request' => request, 'providerState' => 'some state') }
59
-
60
- it "recognises the provider state" do
61
- expect(subject.provider_state).to eq 'some state'
62
- end
63
- end
64
-
65
- context "when there are matching rules" do
66
- let(:hash) { load_json_fixture 'interaction-with-matching-rules.json' }
67
-
68
- subject { Interaction.from_hash hash }
69
-
70
- it "merges the rules with the example for the request" do
71
- expect(subject.request.body['name']).to be_instance_of(Pact::Term)
72
- end
73
-
74
- it "merges the rules with the example for the response" do
75
- expect(subject.response.body['_links']['self']['href']).to be_instance_of(Pact::Term)
76
- end
77
- end
78
- end
79
56
 
80
57
  describe "request_modifies_resource_without_checking_response_body?" do
81
58
 
@@ -25,6 +25,15 @@ module Pact
25
25
  end
26
26
  end
27
27
 
28
+ describe 'with backslashes to a local path' do
29
+ let(:windows_path) { 'spec\support\a_consumer-a_provider.json' }
30
+ let(:unix_path) { 'spec/support/a_consumer-a_provider.json' }
31
+
32
+ it 'transforms them to forward slashes' do
33
+ expect(PactFile.read(windows_path)).to eq PactFile.read(unix_path)
34
+ end
35
+ end
36
+
28
37
  context 'without basic authentication' do
29
38
  before do
30
39
  stub_request(:get, uri_without_userinfo).to_return(body: pact_content)
@@ -72,6 +72,15 @@ module Pact
72
72
  expect(subject.difference(other).keys).to contain_exactly(:"param[a]", :"param[a][aa]", :"param[a][bb]")
73
73
  end
74
74
  end
75
+
76
+ context "when there is an ArrayLike" do
77
+ let(:query) { { param: Pact.each_like("1") } }
78
+ let(:other) { QueryString.new('param=1&param=2') }
79
+
80
+ it 'returns an empty diff' do
81
+ expect(subject.difference(other)).to be_empty
82
+ end
83
+ end
75
84
  end
76
85
  end
77
86
 
@@ -82,6 +91,20 @@ module Pact
82
91
  end
83
92
 
84
93
  describe "#to_json" do
94
+ context "when the query contains an ArrayLike" do
95
+ let(:query) { { foo: Pact.each_like("1"), bar: "2" } }
96
+ let(:expected_json) do
97
+ {
98
+ foo: Pact.each_like("1"),
99
+ bar: ["2"]
100
+ }.to_json
101
+ end
102
+
103
+ it "serialises the ArrayLike without wrapping an array around it" do
104
+ expect(subject.to_json).to eq expected_json
105
+ end
106
+ end
107
+
85
108
  context "when the query contains a Pact::Term" do
86
109
  let(:term) { Pact::Term.new(generate: "thing", matcher: /th/) }
87
110
  let(:query) { { param: term } }
@@ -0,0 +1,36 @@
1
+ require 'pact/matchers/multipart_form_diff_formatter'
2
+
3
+ module Pact
4
+ module Matchers
5
+ describe MultipartFormDiffFormatter do
6
+ describe ".call" do
7
+ subject { MultipartFormDiffFormatter.call(diff, options)}
8
+
9
+ let(:diff) do
10
+ {
11
+ headers: header_diff,
12
+ body: body_diff
13
+ }
14
+ end
15
+
16
+ let(:header_diff) do
17
+ {
18
+ "Content-Type" => Difference.new("foo", "bar", "Wrong header")
19
+ }
20
+ end
21
+
22
+ let(:body_diff) do
23
+ Difference.new("foo", "bar", "A message")
24
+ end
25
+
26
+ let(:options) { {} }
27
+
28
+ let(:expected_output) { File.read("spec/fixtures/multipart-form-diff.txt")}
29
+
30
+ it "formats the diff" do
31
+ expect(subject).to eq expected_output
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -7,10 +7,16 @@ module Pact
7
7
  subject { Merge.(expected, matching_rules, "$.body") }
8
8
 
9
9
  before do
10
- allow($stderr).to receive(:puts)
10
+ allow($stderr).to receive(:puts) do | message |
11
+ raise "Was not expecting stderr to receive #{message.inspect} in this spec. This may be because of a missed call to log_used_rule in Merge."
12
+ end
11
13
  end
12
14
 
13
15
  describe "no recognised rules" do
16
+ before do
17
+ allow($stderr).to receive(:puts)
18
+ end
19
+
14
20
  let(:expected) do
15
21
  {
16
22
  "_links" => {
@@ -63,6 +69,10 @@ module Pact
63
69
  end
64
70
 
65
71
  describe "type based matching" do
72
+ before do
73
+ allow($stderr).to receive(:puts)
74
+ end
75
+
66
76
  let(:expected) do
67
77
  {
68
78
  "name" => "Mary"
@@ -89,6 +99,10 @@ module Pact
89
99
  describe "regular expressions" do
90
100
 
91
101
  describe "in a hash" do
102
+ before do
103
+ allow($stderr).to receive(:puts)
104
+ end
105
+
92
106
  let(:expected) do
93
107
  {
94
108
  "_links" => {
@@ -178,6 +192,7 @@ module Pact
178
192
  "$.body.alligators[*].*" => { 'match' => 'type'}
179
193
  }
180
194
  end
195
+
181
196
  it "creates a Pact::ArrayLike at the appropriate path" do
182
197
  expect(subject["alligators"]).to be_instance_of(Pact::ArrayLike)
183
198
  expect(subject["alligators"].contents).to eq 'name' => 'Mary'
@@ -259,6 +274,10 @@ module Pact
259
274
  end
260
275
 
261
276
  describe "with an example array with more than one item" do
277
+ before do
278
+ allow(Pact.configuration.error_stream).to receive(:puts)
279
+ end
280
+
262
281
  let(:expected) do
263
282
  {
264
283
 
@@ -277,13 +296,7 @@ module Pact
277
296
  }
278
297
  end
279
298
 
280
- xit "doesn't warn about the min size being ignored" do
281
- expect(Pact.configuration.error_stream).to receive(:puts).once
282
- subject
283
- end
284
-
285
299
  it "warns that the other items will be ignored" do
286
- allow(Pact.configuration.error_stream).to receive(:puts)
287
300
  expect(Pact.configuration.error_stream).to receive(:puts).with(/WARN: Only the first item/)
288
301
  subject
289
302
  end
@@ -0,0 +1,238 @@
1
+ require 'pact/matching_rules/v3/extract'
2
+ require 'pact/support'
3
+
4
+ module Pact
5
+ module MatchingRules::V3
6
+ describe Extract do
7
+
8
+ describe ".call" do
9
+
10
+ subject { Extract.call(matchable) }
11
+
12
+ context "with a Pact::SomethingLike" do
13
+ let(:matchable) do
14
+ {
15
+ body: Pact::SomethingLike.new(foo: 'bar', alligator: { name: 'Mary' })
16
+ }
17
+ end
18
+
19
+ let(:rules) do
20
+ {
21
+ "$.body" => {
22
+ "matchers" => [ {"match" => "type"} ]
23
+ }
24
+ }
25
+ end
26
+
27
+ it "creates a rule that matches by type" do
28
+ expect(subject).to eq rules
29
+ end
30
+ end
31
+
32
+ context "with a Pact::Term" do
33
+ let(:matchable) do
34
+ {
35
+ body: {
36
+ alligator: {
37
+ name: Pact::Term.new(generate: 'Mary', matcher: /.*a/)
38
+ }
39
+ }
40
+ }
41
+ end
42
+
43
+ let(:rules) do
44
+ {
45
+ "$.body.alligator.name" => {
46
+ "matchers" => [ {"match" => "regex", "regex" => ".*a"} ]
47
+ }
48
+ }
49
+ end
50
+
51
+ it "creates a rule that matches by regex" do
52
+ expect(subject).to eq rules
53
+ end
54
+ end
55
+
56
+ context "with a Pact::SomethingLike containing a Term" do
57
+ let(:matchable) do
58
+ {
59
+ body: Pact::SomethingLike.new(
60
+ foo: 'bar',
61
+ alligator: { name: Pact::Term.new(generate: 'Mary', matcher: /.*a/) }
62
+ )
63
+ }
64
+ end
65
+
66
+ let(:rules) do
67
+ {
68
+ "$.body" => {
69
+ "matchers" => [ {"match" => "type"} ]
70
+ },
71
+ "$.body.alligator.name" => {
72
+ "matchers" => [ {"match" => "regex", "regex"=>".*a"} ]
73
+ },
74
+ }
75
+ end
76
+
77
+ it "the match:regex overrides the match:type" do
78
+ expect(subject).to eq rules
79
+ end
80
+ end
81
+
82
+ context "with a Pact::SomethingLike containing an array" do
83
+ let(:matchable) do
84
+ {
85
+ body: Pact::SomethingLike.new(
86
+ alligators: [
87
+ {name: 'Mary'},
88
+ {name: 'Betty'}
89
+ ]
90
+ )
91
+ }
92
+ end
93
+
94
+ let(:rules) do
95
+ {
96
+ "$.body" => {
97
+ "matchers" => [ {"match" => "type"} ]
98
+ }
99
+ }
100
+ end
101
+
102
+ it "lists a rule for each item" do
103
+ expect(subject).to eq rules
104
+ end
105
+ end
106
+
107
+ context "with an ArrayLike" do
108
+ let(:matchable) do
109
+ {
110
+ body: {
111
+ alligators: Pact::ArrayLike.new(
112
+ name: 'Fred'
113
+ )
114
+ }
115
+ }
116
+ end
117
+
118
+ let(:rules) do
119
+ {
120
+ "$.body.alligators" => {
121
+ "matchers" => [ {"min" => 1} ]
122
+ },
123
+ "$.body.alligators[*].*" => {
124
+ "matchers" => [ {"match" => "type"} ]
125
+ }
126
+ }
127
+ end
128
+
129
+ it "lists a rule for all items" do
130
+ expect(subject).to eq rules
131
+ end
132
+ end
133
+
134
+ context "with an ArrayLike with a Pact::Term inside" do
135
+ let(:matchable) do
136
+ {
137
+ body: {
138
+ alligators: Pact::ArrayLike.new(
139
+ name: 'Fred',
140
+ phoneNumber: Pact::Term.new(generate: '1234567', matcher: /\d+/)
141
+ )
142
+ }
143
+ }
144
+ end
145
+
146
+ let(:rules) do
147
+ {
148
+ "$.body.alligators" => {
149
+ "matchers" => [ {"min" => 1} ]
150
+ },
151
+ "$.body.alligators[*].*" => {
152
+ "matchers" => [ {"match" => "type"} ]
153
+ },
154
+ "$.body.alligators[*].phoneNumber" => {
155
+ "matchers" => [ {"match" => "regex", "regex" => "\\d+"} ]
156
+ }
157
+ }
158
+ end
159
+
160
+ it "lists a rule that specifies that the regular expression must match" do
161
+ expect(subject).to eq rules
162
+ end
163
+ end
164
+
165
+ context "with a Pact::QueryString containing a Pact::Term" do
166
+ let(:matchable) do
167
+ {
168
+ query: Pact::QueryString.new(Pact::Term.new(generate: 'foobar', matcher: /foo/))
169
+ }
170
+ end
171
+
172
+ let(:rules) do
173
+ {
174
+ "$.query" => {
175
+ "matchers" => [ {"match" => "regex", "regex" => "foo"} ]
176
+ }
177
+ }
178
+ end
179
+
180
+ it "lists a rule that specifies that the regular expression must match" do
181
+ expect(subject).to eq rules
182
+ end
183
+ end
184
+
185
+ context "with a Pact::QueryHash containing a Pact::Term" do
186
+ let(:matchable) do
187
+ {
188
+ query: Pact::QueryHash.new(bar: Pact::Term.new(generate: 'foobar', matcher: /foo/))
189
+ }
190
+ end
191
+
192
+ let(:rules) do
193
+ {
194
+ "$.query.bar[0]" => {
195
+ "matchers" => [ {"match" => "regex", "regex" => "foo"} ]
196
+ }
197
+ }
198
+ end
199
+
200
+ it "lists a rule that specifies that the regular expression must match" do
201
+ expect(subject).to eq rules
202
+ end
203
+ end
204
+
205
+ context "with no special matching" do
206
+ let(:matchable) do
207
+ {
208
+ body: { alligator: { name: 'Mary' } }
209
+ }
210
+ end
211
+
212
+ let(:rules) do
213
+ {}
214
+ end
215
+
216
+
217
+ it "does not create any rules" do
218
+ expect(subject).to eq rules
219
+ end
220
+ end
221
+
222
+ context "with a key containing a dot" do
223
+ let(:matchable) do
224
+ {
225
+ "key" => {
226
+ "key.with.dots" => Pact::SomethingLike.new("foo")
227
+ }
228
+ }
229
+ end
230
+
231
+ it "uses square brackets notation for the key with dots" do
232
+ expect(subject.keys).to include "$.key['key.with.dots']"
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end