pact-support 0.0.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.
- 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
|