pact-support 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +29 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +80 -0
- data/LICENSE.txt +22 -0
- data/README.md +4 -0
- data/Rakefile +4 -0
- data/lib/pact/configuration.rb +164 -0
- data/lib/pact/consumer/request.rb +27 -0
- data/lib/pact/consumer_contract.rb +1 -0
- data/lib/pact/consumer_contract/consumer_contract.rb +114 -0
- data/lib/pact/consumer_contract/file_name.rb +19 -0
- data/lib/pact/consumer_contract/headers.rb +51 -0
- data/lib/pact/consumer_contract/interaction.rb +73 -0
- data/lib/pact/consumer_contract/pact_file.rb +24 -0
- data/lib/pact/consumer_contract/request.rb +73 -0
- data/lib/pact/consumer_contract/response.rb +51 -0
- data/lib/pact/consumer_contract/service_consumer.rb +28 -0
- data/lib/pact/consumer_contract/service_provider.rb +28 -0
- data/lib/pact/logging.rb +14 -0
- data/lib/pact/matchers.rb +1 -0
- data/lib/pact/matchers/actual_type.rb +16 -0
- data/lib/pact/matchers/base_difference.rb +37 -0
- data/lib/pact/matchers/differ.rb +153 -0
- data/lib/pact/matchers/difference.rb +13 -0
- data/lib/pact/matchers/difference_indicator.rb +26 -0
- data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
- data/lib/pact/matchers/expected_type.rb +35 -0
- data/lib/pact/matchers/index_not_found.rb +15 -0
- data/lib/pact/matchers/list_diff_formatter.rb +101 -0
- data/lib/pact/matchers/matchers.rb +139 -0
- data/lib/pact/matchers/no_diff_indicator.rb +18 -0
- data/lib/pact/matchers/regexp_difference.rb +13 -0
- data/lib/pact/matchers/type_difference.rb +16 -0
- data/lib/pact/matchers/unexpected_index.rb +11 -0
- data/lib/pact/matchers/unexpected_key.rb +11 -0
- data/lib/pact/matchers/unix_diff_formatter.rb +114 -0
- data/lib/pact/reification.rb +28 -0
- data/lib/pact/rspec.rb +53 -0
- data/lib/pact/shared/active_support_support.rb +51 -0
- data/lib/pact/shared/dsl.rb +76 -0
- data/lib/pact/shared/jruby_support.rb +18 -0
- data/lib/pact/shared/json_differ.rb +15 -0
- data/lib/pact/shared/key_not_found.rb +15 -0
- data/lib/pact/shared/null_expectation.rb +31 -0
- data/lib/pact/shared/request.rb +97 -0
- data/lib/pact/shared/text_differ.rb +14 -0
- data/lib/pact/something_like.rb +49 -0
- data/lib/pact/support.rb +9 -0
- data/lib/pact/support/version.rb +5 -0
- data/lib/pact/symbolize_keys.rb +12 -0
- data/lib/pact/term.rb +85 -0
- data/lib/tasks/pact.rake +29 -0
- data/pact-support.gemspec +35 -0
- data/spec/lib/pact/consumer/request_spec.rb +25 -0
- data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +58 -0
- data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +141 -0
- data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
- data/spec/lib/pact/consumer_contract/interaction_spec.rb +151 -0
- data/spec/lib/pact/consumer_contract/request_spec.rb +329 -0
- data/spec/lib/pact/consumer_contract/response_spec.rb +73 -0
- data/spec/lib/pact/matchers/differ_spec.rb +215 -0
- data/spec/lib/pact/matchers/difference_spec.rb +22 -0
- data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +90 -0
- data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
- data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +120 -0
- data/spec/lib/pact/matchers/matchers_spec.rb +500 -0
- data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
- data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
- data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
- data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
- data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +216 -0
- data/spec/lib/pact/reification_spec.rb +67 -0
- data/spec/lib/pact/shared/dsl_spec.rb +86 -0
- data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
- data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
- data/spec/lib/pact/shared/request_spec.rb +196 -0
- data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
- data/spec/lib/pact/something_like_spec.rb +21 -0
- data/spec/lib/pact/term_spec.rb +89 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/a_consumer-a_producer.json +32 -0
- data/spec/support/a_consumer-a_provider.json +32 -0
- data/spec/support/active_support_if_configured.rb +6 -0
- data/spec/support/case-insensitive-response-header-matching.json +21 -0
- data/spec/support/consumer_contract_template.json +24 -0
- data/spec/support/dsl_spec_support.rb +7 -0
- data/spec/support/factories.rb +82 -0
- data/spec/support/generated_index.md +4 -0
- data/spec/support/generated_markdown.md +55 -0
- data/spec/support/interaction_view_model.json +63 -0
- data/spec/support/interaction_view_model_with_terms.json +50 -0
- data/spec/support/markdown_pact.json +48 -0
- data/spec/support/missing_provider_states_output.txt +25 -0
- data/spec/support/options.json +21 -0
- data/spec/support/shared_examples_for_request.rb +94 -0
- data/spec/support/spec_support.rb +20 -0
- data/spec/support/stubbing.json +22 -0
- data/spec/support/term.json +48 -0
- data/spec/support/test_app_fail.json +61 -0
- data/spec/support/test_app_pass.json +38 -0
- data/spec/support/test_app_with_right_content_type_differ.json +23 -0
- data/tasks/spec.rake +6 -0
- metadata +401 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pact/consumer_contract/headers'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
describe Headers do
|
6
|
+
|
7
|
+
describe "initialize" do
|
8
|
+
|
9
|
+
context "with duplicate headers" do
|
10
|
+
|
11
|
+
subject { Headers.new('Content-Type' => 'application/hippo', 'CONTENT-TYPE' => 'application/giraffe') }
|
12
|
+
|
13
|
+
it "raises an error" do
|
14
|
+
expect { subject }.to raise_error DuplicateHeaderError, /Content\-Type.*CONTENT\-TYPE/
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with a symbol as a header name" do
|
20
|
+
|
21
|
+
subject { Headers.new(:'content-type' => 'application/hippo') }
|
22
|
+
|
23
|
+
it "converts the header name to a String" do
|
24
|
+
expect( subject.to_hash ).to eq 'content-type' => 'application/hippo'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with a nil header name" do
|
30
|
+
|
31
|
+
subject { Headers.new(nil => 'application/hippo') }
|
32
|
+
|
33
|
+
it "raises an error" do
|
34
|
+
expect{ subject }.to raise_error InvalidHeaderNameTypeError
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with a boolean header name" do
|
40
|
+
|
41
|
+
subject { Headers.new(false => 'application/hippo') }
|
42
|
+
|
43
|
+
it "raises an error" do
|
44
|
+
expect{ subject }.to raise_error InvalidHeaderNameTypeError
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "[]" do
|
52
|
+
|
53
|
+
subject { Headers.new 'Content-Type' => 'application/hippo' }
|
54
|
+
|
55
|
+
it "is case insensitive as HTTP headers are case insensitive" do
|
56
|
+
expect(subject['Content-Type']).to eq('application/hippo')
|
57
|
+
expect(subject['CONTENT-TYPE']).to eq('application/hippo')
|
58
|
+
expect(subject['content-type']).to eq('application/hippo')
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "fetch" do
|
64
|
+
|
65
|
+
subject { Headers.new 'Content-Type' => 'application/hippo' }
|
66
|
+
|
67
|
+
it "is case insensitive as HTTP headers are case insensitive" do
|
68
|
+
expect(subject.fetch('Content-Type')).to eq('application/hippo')
|
69
|
+
expect(subject.fetch('CONTENT-TYPE')).to eq('application/hippo')
|
70
|
+
expect(subject.fetch('content-type')).to eq('application/hippo')
|
71
|
+
expect(subject.fetch('Content-Length','1')).to eq('1')
|
72
|
+
expect { subject.fetch('Content-Length')}.to raise_error KeyError
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "key?" do
|
78
|
+
|
79
|
+
subject { Headers.new 'Content-Type' => 'application/hippo' }
|
80
|
+
|
81
|
+
it "is case insensitive as HTTP headers are case insensitive" do
|
82
|
+
expect(subject.key?('CONTENT-TYPE')).to be true
|
83
|
+
expect(subject.key?('CONTENT-LENGTH')).to be false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "has_key?" do
|
88
|
+
|
89
|
+
subject { Headers.new 'Content-Type' => 'application/hippo' }
|
90
|
+
|
91
|
+
it "is case insensitive as HTTP headers are case insensitive" do
|
92
|
+
expect(subject.has_key?('CONTENT-TYPE')).to be true
|
93
|
+
expect(subject.has_key?('CONTENT-LENGTH')).to be false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "[]=" do
|
98
|
+
|
99
|
+
subject { Headers.new }
|
100
|
+
|
101
|
+
it "does not allow modification" do
|
102
|
+
expect{ subject['Content-Type'] = 'application/hippo' }.to raise_error /frozen/
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pact/reification'
|
3
|
+
require 'pact/consumer_contract/interaction'
|
4
|
+
|
5
|
+
module Pact
|
6
|
+
module Consumer
|
7
|
+
|
8
|
+
describe Interaction do
|
9
|
+
|
10
|
+
let(:request) { {method: 'get', path: 'path'} }
|
11
|
+
let(:response) { {} }
|
12
|
+
|
13
|
+
describe "==" do
|
14
|
+
subject { InteractionFactory.create }
|
15
|
+
context "when other is the same" do
|
16
|
+
let(:other) { InteractionFactory.create }
|
17
|
+
it "returns true" do
|
18
|
+
expect(subject == other).to be true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
context "when other is not the same" do
|
22
|
+
let(:other) { InteractionFactory.create(:request => {:path => '/a_different_path'}) }
|
23
|
+
it "returns false" do
|
24
|
+
expect(subject == other).to be false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "matches_criteria?" do
|
30
|
+
subject { InteractionFactory.create(:description => 'a request for food') }
|
31
|
+
context "by description" do
|
32
|
+
context "when the interaction matches" do
|
33
|
+
it "returns true" do
|
34
|
+
expect(subject.matches_criteria?(:description => /request.*food/)).to be true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
context "when the interaction does not match" do
|
38
|
+
it "returns false" do
|
39
|
+
expect(subject.matches_criteria?(:description => /blah/)).to be false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "from_hash" do
|
46
|
+
context "when providerState has been used instead of provider_state" do
|
47
|
+
|
48
|
+
subject { Interaction.from_hash('response' => response, 'request' => request, 'providerState' => 'some state') }
|
49
|
+
|
50
|
+
it "recognises the provider state" do
|
51
|
+
expect(subject.provider_state).to eq 'some state'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "to JSON" do
|
57
|
+
let(:request) do
|
58
|
+
{
|
59
|
+
method: 'post',
|
60
|
+
path: '/foo',
|
61
|
+
body: Term.new(generate: 'waffle', matcher: /ffl/),
|
62
|
+
headers: { 'Content-Type' => 'application/json' },
|
63
|
+
query: '',
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
let(:response) do
|
68
|
+
{ baz: /qux/, wiffle: Term.new(generate: 'wiffle', matcher: /iff/) }
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:parsed_result) do
|
72
|
+
JSON.load(subject.to_json)
|
73
|
+
end
|
74
|
+
|
75
|
+
subject { Interaction.from_hash('response' => response, 'request' => request) }
|
76
|
+
|
77
|
+
it "contains the request" do
|
78
|
+
expect(parsed_result['request']).to eq({
|
79
|
+
'method' => 'post',
|
80
|
+
'path' => '/foo',
|
81
|
+
'headers' => {
|
82
|
+
'Content-Type' => 'application/json'
|
83
|
+
},
|
84
|
+
'body' => Term.new(generate: 'waffle', matcher: /ffl/),
|
85
|
+
'query' => ''
|
86
|
+
})
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "response" do
|
90
|
+
|
91
|
+
it "serialises regexes" do
|
92
|
+
expect(parsed_result['response']['baz']).to eql /qux/
|
93
|
+
end
|
94
|
+
|
95
|
+
it "serialises terms" do
|
96
|
+
term = Term.new(generate:'wiffle', matcher: /iff/)
|
97
|
+
parsed_term = parsed_result['response']['wiffle']
|
98
|
+
expect(term.matcher).to eql parsed_term.matcher
|
99
|
+
expect(term.generate).to eql parsed_term.generate
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "request_modifies_resource_without_checking_response_body?" do
|
107
|
+
|
108
|
+
let(:interaction) { Interaction.new(request: request, response: response)}
|
109
|
+
|
110
|
+
subject { interaction.request_modifies_resource_without_checking_response_body?}
|
111
|
+
|
112
|
+
context "when the request modifies the resource and the response allows any value in body" do
|
113
|
+
let(:request) { instance_double(Pact::Request::Expected, modifies_resource?: true) }
|
114
|
+
let(:response) { instance_double(Pact::Response, body_allows_any_value?: true) }
|
115
|
+
|
116
|
+
it "returns true" do
|
117
|
+
expect(subject).to be true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when the request modifies the resource and the response does not allow any value in body" do
|
122
|
+
let(:request) { instance_double(Pact::Request::Expected, modifies_resource?: true) }
|
123
|
+
let(:response) { instance_double(Pact::Response, body_allows_any_value?: false) }
|
124
|
+
|
125
|
+
it "returns false" do
|
126
|
+
expect(subject).to be false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when the request does not modifies the resource and the response does not allow any value in body" do
|
131
|
+
let(:request) { instance_double(Pact::Request::Expected, modifies_resource?: false) }
|
132
|
+
let(:response) { instance_double(Pact::Response, body_allows_any_value?: false) }
|
133
|
+
|
134
|
+
it "returns false" do
|
135
|
+
expect(subject).to be false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "when the request does not modifies the resource and the response allows any value in body" do
|
140
|
+
let(:request) { instance_double(Pact::Request::Expected, modifies_resource?: false) }
|
141
|
+
let(:response) { instance_double(Pact::Response, body_allows_any_value?: true) }
|
142
|
+
|
143
|
+
it "returns false" do
|
144
|
+
expect(subject).to be false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pact/consumer_contract/request'
|
3
|
+
require 'support/shared_examples_for_request'
|
4
|
+
require 'pact/consumer/request'
|
5
|
+
|
6
|
+
module Pact
|
7
|
+
|
8
|
+
describe Request::Expected do
|
9
|
+
it_behaves_like "a request"
|
10
|
+
|
11
|
+
let(:raw_request) do
|
12
|
+
{
|
13
|
+
'method' => 'get',
|
14
|
+
'path' => '/mallory'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "from_hash" do
|
19
|
+
context "when optional field are not defined" do
|
20
|
+
subject { described_class.from_hash(raw_request) }
|
21
|
+
it "sets their values to NullExpectation" do
|
22
|
+
expect(subject.body).to be_instance_of(Pact::NullExpectation)
|
23
|
+
expect(subject.query).to be_instance_of(Pact::NullExpectation)
|
24
|
+
expect(subject.headers).to be_instance_of(Pact::NullExpectation)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "as_json" do
|
30
|
+
subject { Request::Expected.new(:get, '/path', {:header => 'value'}, {:body => 'yeah'}, "query", {some: 'options'}) }
|
31
|
+
context "with options" do
|
32
|
+
it "does not include the options because they are a temporary hack and should leave no trace of themselves in the pact file" do
|
33
|
+
expect(subject.as_json.key?(:options)).to be false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "matching to actual requests" do
|
39
|
+
|
40
|
+
subject { Request::Expected.new(expected_method, expected_path, expected_headers, expected_body, expected_query, options) }
|
41
|
+
let(:options) { {} }
|
42
|
+
|
43
|
+
let(:expected_method) { 'get' }
|
44
|
+
let(:expected_path) { '/foo' }
|
45
|
+
let(:expected_headers) { Pact::NullExpectation.new }
|
46
|
+
let(:expected_body) { Pact::NullExpectation.new }
|
47
|
+
let(:expected_query) { '' }
|
48
|
+
|
49
|
+
let(:actual_request) { Consumer::Request::Actual.new(actual_method, actual_path, actual_headers, actual_body, actual_query) }
|
50
|
+
|
51
|
+
let(:actual_method) { 'get' }
|
52
|
+
let(:actual_path) { '/foo' }
|
53
|
+
let(:actual_headers) { {} }
|
54
|
+
let(:actual_body) { '' }
|
55
|
+
let(:actual_query) { '' }
|
56
|
+
|
57
|
+
it "matches identical requests" do
|
58
|
+
expect(subject.matches? actual_request).to be true
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when the methods are the same but one is symbolized" do
|
62
|
+
let(:expected_method) { :get }
|
63
|
+
let(:actual_method) { 'get' }
|
64
|
+
|
65
|
+
it "matches" do
|
66
|
+
expect(subject.matches? actual_request).to be true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when the methods are different" do
|
71
|
+
let(:expected_method) { 'get' }
|
72
|
+
let(:actual_method) { 'post' }
|
73
|
+
|
74
|
+
it "does not match" do
|
75
|
+
expect(subject.matches? actual_request).to be false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when the methods are the same but different case" do
|
80
|
+
let(:expected_method) { 'get' }
|
81
|
+
let(:actual_method) { 'GET' }
|
82
|
+
|
83
|
+
it "matches" do
|
84
|
+
expect(subject.matches? actual_request).to be true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when the paths are different" do
|
89
|
+
let(:expected_path) { '/foo' }
|
90
|
+
let(:actual_path) { '/bar' }
|
91
|
+
|
92
|
+
it "does not match" do
|
93
|
+
expect(subject.matches? actual_request).to be false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when the paths vary only by a trailing slash" do
|
98
|
+
let(:expected_path) { '/foo' }
|
99
|
+
let(:actual_path) { '/foo/' }
|
100
|
+
|
101
|
+
it "matches" do
|
102
|
+
expect(subject.matches? actual_request).to be true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when the expected body is nil and the actual body is empty" do
|
107
|
+
let(:expected_body) { nil }
|
108
|
+
let(:actual_body) { '' }
|
109
|
+
|
110
|
+
it "does not match" do
|
111
|
+
expect(subject.matches? actual_request).to be false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when the expected body has no expectation and the actual body is empty" do
|
116
|
+
let(:expected_body) { Pact::NullExpectation.new }
|
117
|
+
let(:actual_body) { '' }
|
118
|
+
|
119
|
+
it "matches" do
|
120
|
+
expect(subject.matches? actual_request).to be true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when the expected body is nested and the actual body is nil" do
|
125
|
+
let(:expected_body) do
|
126
|
+
{
|
127
|
+
a: 'a'
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:actual_body) { nil }
|
132
|
+
|
133
|
+
it "does not match" do
|
134
|
+
expect(subject.matches? actual_request).to be false
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when the bodies are different" do
|
139
|
+
let(:expected_body) { 'foo' }
|
140
|
+
let(:actual_body) { 'bar' }
|
141
|
+
|
142
|
+
it "does not match" do
|
143
|
+
expect(subject.matches? actual_request).to be false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when the expected body contains matching regexes" do
|
148
|
+
let(:expected_body) do
|
149
|
+
{
|
150
|
+
name: 'Bob',
|
151
|
+
customer_id: /CN.*/
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
let(:actual_body) do
|
156
|
+
{
|
157
|
+
name: 'Bob',
|
158
|
+
customer_id: 'CN1234'
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
it "matches" do
|
163
|
+
expect(subject.matches? actual_request).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when the expected body contains non-matching regexes" do
|
168
|
+
let(:expected_body) do
|
169
|
+
{
|
170
|
+
name: 'Bob',
|
171
|
+
customer_id: /foo/
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
175
|
+
let(:actual_body) do
|
176
|
+
{
|
177
|
+
name: 'Bob',
|
178
|
+
customer_id: 'CN1234'
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
it "does not match" do
|
183
|
+
expect(subject.matches? actual_request).to be false
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "when the expected body contains matching terms" do
|
188
|
+
let(:expected_body) do
|
189
|
+
{
|
190
|
+
name: 'Bob',
|
191
|
+
customer_id: Term.new(matcher: /CN.*/, generate: 'CN789')
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
let(:actual_body) do
|
196
|
+
{
|
197
|
+
name: 'Bob',
|
198
|
+
customer_id: 'CN1234'
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
it "matches" do
|
203
|
+
expect(subject.matches? actual_request).to be true
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "when the expected body contains non-matching terms" do
|
208
|
+
let(:expected_body) do
|
209
|
+
{
|
210
|
+
name: 'Bob',
|
211
|
+
customer_id: Term.new(matcher: /foo/, generate: 'fooool')
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
let(:actual_body) do
|
216
|
+
{
|
217
|
+
name: 'Bob',
|
218
|
+
customer_id: 'CN1234'
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
it "does not match" do
|
223
|
+
expect(subject.matches? actual_request).to be false
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "when the expected body contains non-matching arrays" do
|
228
|
+
let(:expected_body) do
|
229
|
+
{
|
230
|
+
name: 'Robert',
|
231
|
+
nicknames: ['Bob', 'Bobert']
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
let(:actual_body) do
|
236
|
+
{
|
237
|
+
name: 'Bob',
|
238
|
+
nicknames: ['Bob']
|
239
|
+
}
|
240
|
+
end
|
241
|
+
|
242
|
+
it "does not match" do
|
243
|
+
expect(subject.matches? actual_request).to be false
|
244
|
+
end
|
245
|
+
end
|
246
|
+
context "when the expected body contains non-matching hash where one field contains a substring of the other" do
|
247
|
+
let(:expected_body) do
|
248
|
+
{
|
249
|
+
name: 'Robert',
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
let(:actual_body) do
|
254
|
+
{
|
255
|
+
name: 'Rob'
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
it "does not match" do
|
260
|
+
expect(subject.matches? actual_request).to be false
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context "when the expected body contains matching arrays" do
|
265
|
+
let(:expected_body) do
|
266
|
+
{
|
267
|
+
name: 'Robert',
|
268
|
+
nicknames: ['Bob', 'Bobert']
|
269
|
+
}
|
270
|
+
end
|
271
|
+
|
272
|
+
let(:actual_body) do
|
273
|
+
{
|
274
|
+
name: 'Robert',
|
275
|
+
nicknames: ['Bob', 'Bobert']
|
276
|
+
}
|
277
|
+
end
|
278
|
+
|
279
|
+
it "does not match" do
|
280
|
+
expect(subject.matches? actual_request).to be true
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context "when the queries are different" do
|
285
|
+
let(:expected_query) { 'foo' }
|
286
|
+
let(:actual_query) { 'bar' }
|
287
|
+
|
288
|
+
it "does not match" do
|
289
|
+
expect(subject.matches? actual_request).to be false
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context 'when there is no query expectation' do
|
294
|
+
let(:expected_query) { Pact::NullExpectation.new }
|
295
|
+
let(:actual_query) { 'bar' }
|
296
|
+
|
297
|
+
it 'matches' do
|
298
|
+
expect(subject.matches? actual_request).to be true
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
context "when a string is expected, but a number is found" do
|
303
|
+
let(:actual_body) { { thing: 123} }
|
304
|
+
let(:expected_body) { { thing: "123" } }
|
305
|
+
|
306
|
+
it 'does not match' do
|
307
|
+
expect(subject.matches? actual_request).to be false
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
context "when unexpected keys are found in the body" do
|
312
|
+
let(:expected_body) { {a: 1} }
|
313
|
+
let(:actual_body) { {a: 1, b: 2} }
|
314
|
+
context "when allowing unexpected keys" do
|
315
|
+
let(:options) { {'allow_unexpected_keys_in_body' => true} } #From json, these will be strings
|
316
|
+
it "matches" do
|
317
|
+
expect(subject.matches? actual_request).to be true
|
318
|
+
end
|
319
|
+
end
|
320
|
+
context "when not allowing unexpected keys" do
|
321
|
+
let(:options) { {'allow_unexpected_keys_in_body' => false} }
|
322
|
+
it "does not match" do
|
323
|
+
expect(subject.matches? actual_request).to be false
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|