pacto 0.3.0.pre → 0.3.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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rubocop-todo.yml +0 -27
  4. data/.rubocop.yml +9 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +4 -5
  8. data/CONTRIBUTING.md +112 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +18 -13
  11. data/README.md +157 -101
  12. data/Rakefile +3 -3
  13. data/features/configuration/strict_matchers.feature +97 -0
  14. data/features/evolve/README.md +11 -0
  15. data/features/evolve/existing_services.feature +82 -0
  16. data/features/generate/README.md +5 -0
  17. data/features/generate/generation.feature +28 -0
  18. data/features/steps/pacto_steps.rb +75 -0
  19. data/features/stub/README.md +2 -0
  20. data/features/stub/templates.feature +46 -0
  21. data/features/support/env.rb +11 -5
  22. data/features/validate/README.md +1 -0
  23. data/features/validate/body_only.feature +85 -0
  24. data/features/{journeys/validation.feature → validate/meta_validation.feature} +41 -24
  25. data/features/validate/validation.feature +36 -0
  26. data/lib/pacto.rb +61 -33
  27. data/lib/pacto/contract.rb +18 -15
  28. data/lib/pacto/contract_factory.rb +14 -11
  29. data/lib/pacto/contract_files.rb +17 -0
  30. data/lib/pacto/contract_list.rb +17 -0
  31. data/lib/pacto/contract_validator.rb +29 -0
  32. data/lib/pacto/core/configuration.rb +19 -17
  33. data/lib/pacto/core/contract_registry.rb +43 -0
  34. data/lib/pacto/core/{callback.rb → hook.rb} +3 -3
  35. data/lib/pacto/core/modes.rb +33 -0
  36. data/lib/pacto/core/validation_registry.rb +45 -0
  37. data/lib/pacto/erb_processor.rb +0 -1
  38. data/lib/pacto/extensions.rb +18 -4
  39. data/lib/pacto/generator.rb +34 -49
  40. data/lib/pacto/generator/filters.rb +41 -0
  41. data/lib/pacto/hooks/erb_hook.rb +4 -3
  42. data/lib/pacto/logger.rb +4 -2
  43. data/lib/pacto/meta_schema.rb +4 -2
  44. data/lib/pacto/rake_task.rb +28 -25
  45. data/lib/pacto/request_clause.rb +43 -0
  46. data/lib/pacto/request_pattern.rb +8 -0
  47. data/lib/pacto/response_clause.rb +15 -0
  48. data/lib/pacto/rspec.rb +102 -0
  49. data/lib/pacto/stubs/uri_pattern.rb +23 -0
  50. data/lib/pacto/stubs/webmock_adapter.rb +69 -0
  51. data/lib/pacto/stubs/webmock_helper.rb +71 -0
  52. data/lib/pacto/ui.rb +7 -0
  53. data/lib/pacto/uri.rb +9 -0
  54. data/lib/pacto/validation.rb +57 -0
  55. data/lib/pacto/validators/body_validator.rb +41 -0
  56. data/lib/pacto/validators/request_body_validator.rb +23 -0
  57. data/lib/pacto/validators/response_body_validator.rb +23 -0
  58. data/lib/pacto/validators/response_header_validator.rb +49 -0
  59. data/lib/pacto/validators/response_status_validator.rb +24 -0
  60. data/lib/pacto/version.rb +1 -1
  61. data/pacto.gemspec +33 -29
  62. data/resources/contract_schema.json +8 -176
  63. data/resources/draft-03.json +174 -0
  64. data/spec/integration/data/strict_contract.json +2 -2
  65. data/spec/integration/e2e_spec.rb +22 -31
  66. data/spec/integration/rspec_spec.rb +94 -0
  67. data/spec/integration/templating_spec.rb +9 -12
  68. data/{lib → spec}/pacto/server.rb +0 -0
  69. data/{lib → spec}/pacto/server/dummy.rb +11 -8
  70. data/{lib → spec}/pacto/server/playback_servlet.rb +1 -1
  71. data/spec/spec_helper.rb +2 -0
  72. data/spec/unit/hooks/erb_hook_spec.rb +15 -15
  73. data/spec/unit/pacto/configuration_spec.rb +2 -10
  74. data/spec/unit/pacto/contract_factory_spec.rb +16 -13
  75. data/spec/unit/pacto/contract_files_spec.rb +42 -0
  76. data/spec/unit/pacto/contract_list_spec.rb +35 -0
  77. data/spec/unit/pacto/contract_spec.rb +43 -44
  78. data/spec/unit/pacto/contract_validator_spec.rb +85 -0
  79. data/spec/unit/pacto/core/configuration_spec.rb +4 -11
  80. data/spec/unit/pacto/core/contract_registry_spec.rb +119 -0
  81. data/spec/unit/pacto/core/modes_spec.rb +18 -0
  82. data/spec/unit/pacto/core/validation_registry_spec.rb +76 -0
  83. data/spec/unit/pacto/core/validation_spec.rb +60 -0
  84. data/spec/unit/pacto/extensions_spec.rb +14 -23
  85. data/spec/unit/pacto/generator/filters_spec.rb +99 -0
  86. data/spec/unit/pacto/generator_spec.rb +34 -73
  87. data/spec/unit/pacto/meta_schema_spec.rb +46 -6
  88. data/spec/unit/pacto/pacto_spec.rb +17 -15
  89. data/spec/unit/pacto/{request_spec.rb → request_clause_spec.rb} +32 -44
  90. data/spec/unit/pacto/request_pattern_spec.rb +22 -0
  91. data/spec/unit/pacto/response_clause_spec.rb +54 -0
  92. data/spec/unit/pacto/stubs/uri_pattern_spec.rb +28 -0
  93. data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +205 -0
  94. data/spec/unit/pacto/stubs/webmock_helper_spec.rb +20 -0
  95. data/spec/unit/pacto/uri_spec.rb +20 -0
  96. data/spec/unit/pacto/validators/body_validator_spec.rb +105 -0
  97. data/spec/unit/pacto/validators/response_header_validator_spec.rb +94 -0
  98. data/spec/unit/pacto/validators/response_status_validator_spec.rb +20 -0
  99. metadata +230 -146
  100. data/features/generation/generation.feature +0 -25
  101. data/lib/pacto/core/contract_repository.rb +0 -44
  102. data/lib/pacto/hash_merge_processor.rb +0 -14
  103. data/lib/pacto/request.rb +0 -57
  104. data/lib/pacto/response.rb +0 -63
  105. data/lib/pacto/response_adapter.rb +0 -24
  106. data/lib/pacto/stubs/built_in.rb +0 -57
  107. data/spec/unit/pacto/core/contract_repository_spec.rb +0 -133
  108. data/spec/unit/pacto/hash_merge_processor_spec.rb +0 -20
  109. data/spec/unit/pacto/response_adapter_spec.rb +0 -25
  110. data/spec/unit/pacto/response_spec.rb +0 -201
  111. data/spec/unit/pacto/stubs/built_in_spec.rb +0 -168
@@ -0,0 +1,60 @@
1
+ module Pacto
2
+ describe Validation do
3
+ let(:request) { double('request') }
4
+ let(:response) { double('response') }
5
+ let(:contract) { double('contract') }
6
+ let(:validation_results) { double('validation_results') }
7
+
8
+ before(:each) do
9
+ allow(contract).to receive(:validate_consumer)
10
+ end
11
+
12
+ it 'stores the request, response and contract' do
13
+ validation = Pacto::Validation.new request, response, contract
14
+ expect(validation.request).to eq request
15
+ expect(validation.response).to eq response
16
+ end
17
+
18
+ it 'generates and stores the results' do
19
+ expect(contract).to receive(:validate_consumer).with(request, response).and_return(validation_results)
20
+ validation = Pacto::Validation.new request, response, contract
21
+ expect(validation.results).to eq validation_results
22
+ end
23
+
24
+ describe '#successful?' do
25
+ subject(:validation) do
26
+ Pacto::Validation.new request, response, contract
27
+ end
28
+
29
+ it 'returns true if there were no validation errors' do
30
+ expect(validation.successful?).to be_true
31
+ end
32
+
33
+ it 'returns false if there were validation errors' do
34
+ expect(validation.successful?).to be_true
35
+ end
36
+ end
37
+
38
+ describe '#against_contract?' do
39
+ it 'returns nil if there was no contract' do
40
+ validation = Pacto::Validation.new request, response, nil
41
+ expect(validation.against_contract? 'a').to be_nil
42
+ end
43
+
44
+ it 'returns the contract with an exact string name match' do
45
+ allow(contract).to receive(:file).and_return('foo')
46
+ validation = Pacto::Validation.new request, response, contract
47
+ expect(validation.against_contract? 'foo').to eq(contract)
48
+ expect(validation.against_contract? 'bar').to be_nil
49
+ end
50
+
51
+ it 'returns the contract if there is a regex match' do
52
+ allow(contract).to receive(:file).and_return 'foobar'
53
+ validation = Pacto::Validation.new request, response, contract
54
+ expect(validation.against_contract?(/foo/)).to eq(contract)
55
+ expect(validation.against_contract?(/bar/)).to eq(contract)
56
+ expect(validation.against_contract?(/baz/)).to be_nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,32 +1,23 @@
1
1
  module Pacto
2
2
  module Extensions
3
3
  describe HashSubsetOf do
4
- describe '#subset_of?' do
5
- context 'when the other hash is the same' do
6
- it 'returns true' do
7
- expect({:a => 'a'}).to be_subset_of({:a => 'a'})
8
- end
9
- end
10
-
11
- context 'when the other hash is a subset' do
12
- it 'returns true' do
13
- expect({:a => 'a'}).to be_subset_of({:a => 'a', :b => 'b'})
14
- end
15
- end
16
-
17
- context 'when the other hash is not a subset' do
18
- it 'returns false' do
19
- expect({:a => 'a'}.subset_of?({:a => 'b'})).to be_false
20
- end
4
+ describe '#normalize_keys' do
5
+ it 'turns keys into downcased strings' do
6
+ expect({:A => 'a'}.normalize_keys).to eq('a' => 'a')
7
+ expect({:a => 'a'}.normalize_keys).to eq('a' => 'a')
8
+ expect({'A' => 'a'}.normalize_keys).to eq('a' => 'a')
9
+ expect({'a' => 'a'}.normalize_keys).to eq('a' => 'a')
21
10
  end
22
11
  end
23
12
 
24
- describe '#normalize_keys' do
25
- it 'turns keys into downcased strings' do
26
- expect({:A => 'a'}.normalize_keys).to eq({'a' => 'a'})
27
- expect({:a => 'a'}.normalize_keys).to eq({'a' => 'a'})
28
- expect({'A' => 'a'}.normalize_keys).to eq({'a' => 'a'})
29
- expect({'a' => 'a'}.normalize_keys).to eq({'a' => 'a'})
13
+ describe '#normalize_header_keys' do
14
+ it 'matches headers to the style in the RFC documentation' do
15
+ expect(Pacto::Extensions.normalize_header_keys(:'user-agent' => 'a')).to eq('User-Agent' => 'a') # rubocop:disable SymbolName
16
+ expect(Pacto::Extensions.normalize_header_keys(:user_agent => 'a')).to eq('User-Agent' => 'a')
17
+ expect(Pacto::Extensions.normalize_header_keys('User-Agent' => 'a')).to eq('User-Agent' => 'a')
18
+ expect(Pacto::Extensions.normalize_header_keys('user-agent' => 'a')).to eq('User-Agent' => 'a')
19
+ expect(Pacto::Extensions.normalize_header_keys('user_agent' => 'a')).to eq('User-Agent' => 'a')
20
+ expect(Pacto::Extensions.normalize_header_keys('USER_AGENT' => 'a')).to eq('User-Agent' => 'a')
30
21
  end
31
22
  end
32
23
  end
@@ -0,0 +1,99 @@
1
+ module Pacto
2
+ class Generator
3
+ describe Filters do
4
+ let(:record_host) do
5
+ 'http://example.com'
6
+ end
7
+ let(:request) do
8
+ RequestClause.new(
9
+ record_host,
10
+ 'method' => 'GET',
11
+ 'path' => '/abcd',
12
+ 'headers' => {
13
+ 'Server' => ['example.com'],
14
+ 'Connection' => ['Close'],
15
+ 'Content-Length' => [1234],
16
+ 'Via' => ['Some Proxy'],
17
+ 'User-Agent' => ['rspec']
18
+ },
19
+ 'params' => {
20
+ 'apikey' => "<%= ENV['MY_API_KEY'] %>"
21
+ }
22
+ )
23
+ end
24
+ let(:varies) { ['User-Agent'] }
25
+ let(:response) do
26
+ Faraday::Response.new(
27
+ :status => 200,
28
+ :response_headers => {
29
+ 'Date' => Time.now.rfc2822,
30
+ 'Last-Modified' => Time.now.rfc2822,
31
+ 'ETag' => 'abc123',
32
+ 'Server' => ['Fake Server'],
33
+ 'Content-Type' => ['application/json'],
34
+ 'Vary' => varies
35
+ },
36
+ :body => double('dummy body')
37
+ )
38
+ end
39
+
40
+ describe '#filter_request_headers' do
41
+ subject(:filtered_request_headers) { described_class.new.filter_request_headers(request, response).keys.map(&:downcase) }
42
+ it 'keeps important request headers' do
43
+ expect(filtered_request_headers).to include 'user-agent'
44
+ end
45
+
46
+ it 'filters informational request headers' do
47
+ expect(filtered_request_headers).not_to include 'via'
48
+ expect(filtered_request_headers).not_to include 'date'
49
+ expect(filtered_request_headers).not_to include 'server'
50
+ expect(filtered_request_headers).not_to include 'content-length'
51
+ expect(filtered_request_headers).not_to include 'connection'
52
+ end
53
+
54
+ context 'multiple Vary elements' do
55
+ context 'as a single string' do
56
+ let(:varies) do
57
+ ['User-Agent,Via']
58
+ end
59
+ it 'keeps each header' do
60
+ expect(filtered_request_headers).to include 'user-agent'
61
+ expect(filtered_request_headers).to include 'via'
62
+ end
63
+ end
64
+ context 'as multiple items' do
65
+ let(:varies) do
66
+ %w{User-Agent Via}
67
+ end
68
+ it 'keeps each header' do
69
+ expect(filtered_request_headers).to include 'user-agent'
70
+ expect(filtered_request_headers).to include 'via'
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '#filter_response_headers' do
77
+ subject(:filtered_response_headers) { described_class.new.filter_response_headers(request, response).keys.map(&:downcase) }
78
+ it 'keeps important response headers' do
79
+ expect(filtered_response_headers).to include 'content-type'
80
+ end
81
+
82
+ it 'filters connection control headers' do
83
+ expect(filtered_response_headers).not_to include 'content-length'
84
+ expect(filtered_response_headers).not_to include 'via'
85
+ end
86
+
87
+ it 'filters freshness headers' do
88
+ expect(filtered_response_headers).not_to include 'date'
89
+ expect(filtered_response_headers).not_to include 'last-modified'
90
+ expect(filtered_response_headers).not_to include 'eTag'
91
+ end
92
+
93
+ it 'filters x-* headers' do
94
+ expect(filtered_response_headers).not_to include 'x-men'
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,73 +1,53 @@
1
1
  module Pacto
2
2
  describe Generator do
3
- let(:record_host) {
3
+ let(:record_host) do
4
4
  'http://example.com'
5
- }
5
+ end
6
+
6
7
  let(:request) do
7
- Pacto::Request.new(record_host, {
8
- 'method' => 'GET',
9
- 'path' => '/abcd',
10
- 'headers' => {
8
+ Faraday::Request.create :get do |req|
9
+ req.path = '/abcd'
10
+ req.params = { 'apikey' => "<%= ENV['MY_API_KEY'] %>" }
11
+ req.headers = {
11
12
  'Content-Length' => [1234],
12
13
  'Via' => ['Some Proxy'],
13
14
  'User-Agent' => ['rspec']
14
- },
15
- 'params' => []
16
- })
15
+ }
16
+ end
17
17
  end
18
+
18
19
  let(:response_adapter) do
19
- Pacto::ResponseAdapter.new(
20
- OpenStruct.new({
21
- 'status' => 200,
22
- 'headers' => {
23
- 'Date' => [Time.now],
24
- 'Server' => ['Fake Server'],
25
- 'Content-Type' => ['application/json']
26
- },
27
- 'body' => double('dummy body')
28
- })
20
+ Faraday::Response.new(
21
+ :status => 200,
22
+ :response_headers => {
23
+ 'Date' => [Time.now],
24
+ 'Server' => ['Fake Server'],
25
+ 'Content-Type' => ['application/json'],
26
+ 'Vary' => ['User-Agent']
27
+ },
28
+ :body => 'dummy body' # body is just a string
29
29
  )
30
30
  end
31
+ let(:filtered_request_headers) { double('filtered_response_headers') }
32
+ let(:filtered_response_headers) { double('filtered_response_headers') }
31
33
  let(:response_body_schema) { '{"message": "dummy generated schema"}' }
32
34
  let(:version) { 'draft3' }
33
35
  let(:schema_generator) { double('schema_generator') }
34
36
  let(:validator) { double('validator') }
37
+ let(:filters) { double :filters }
35
38
  let(:request_file) { 'request.json' }
36
- let(:generator) { described_class.new version, schema_generator, validator }
39
+ let(:options) { Pacto.configuration.generator_options }
40
+ let(:generator) { described_class.new version, schema_generator, validator, options, filters }
37
41
 
38
- def pretty obj
42
+ def pretty(obj)
39
43
  MultiJson.encode(obj, :pretty => true).gsub(/^$\n/, '')
40
44
  end
41
45
 
42
- describe '#generate' do
43
- let(:request_contract) {
44
- double({
45
- :request => request,
46
- })
47
- }
48
- let(:generated_contract) { double('generated contract') }
46
+ describe '#save' do
49
47
  before do
50
- Pacto.should_receive(:build_from_file).with(request_file, record_host).and_return request_contract
51
- request.should_receive(:execute).and_return response_adapter
52
- end
53
-
54
- it 'parses the request' do
55
- generator.should_receive(:save).with(request_file, request, anything)
56
- generator.generate request_file, record_host
57
- end
58
-
59
- it 'fetches a response' do
60
- generator.should_receive(:save).with(request_file, anything, response_adapter)
61
- generator.generate request_file, record_host
62
- end
63
-
64
- it 'saves the result' do
65
- generator.should_receive(:save).with(request_file, request, response_adapter).and_return generated_contract
66
- expect(generator.generate request_file, record_host).to eq(generated_contract)
48
+ filters.should_receive(:filter_request_headers).with(request, response_adapter).and_return filtered_request_headers
49
+ filters.should_receive(:filter_response_headers).with(request, response_adapter).and_return filtered_response_headers
67
50
  end
68
- end
69
-
70
- describe '#save' do
71
51
  context 'invalid schema' do
72
52
  it 'raises an error if schema generation fails' do
73
53
  JSON::SchemaGenerator.should_receive(:generate).and_raise ArgumentError.new('Could not generate schema')
@@ -82,11 +62,11 @@ module Pacto
82
62
  end
83
63
 
84
64
  context 'valid schema' do
85
- let(:raw_contract) {
86
- JSON::SchemaGenerator.should_receive(:generate).with(request_file, response_adapter.body, 'draft3').and_return response_body_schema
65
+ let(:raw_contract) do
66
+ JSON::SchemaGenerator.should_receive(:generate).with(request_file, response_adapter.body, Pacto.configuration.generator_options).and_return response_body_schema
87
67
  validator.should_receive(:validate).and_return true
88
68
  generator.save request_file, request, response_adapter
89
- }
69
+ end
90
70
  subject(:generated_contract) { JSON.parse raw_contract }
91
71
 
92
72
  it 'sets the body to the generated json-schema' do
@@ -99,17 +79,9 @@ module Pacto
99
79
  expect(generated_request['path']).to eq(request.path)
100
80
  end
101
81
 
102
- it 'keeps important request headers' do
103
- saved_headers = subject['request']['headers']
104
- expect(saved_headers.keys).to include 'User-Agent'
105
- end
106
-
107
- it 'filters informational request headers' do
108
- saved_headers = subject['request']['headers']
109
- expect(saved_headers).not_to include 'Date'
110
- expect(saved_headers).not_to include 'Server'
111
- expect(saved_headers).not_to include 'Content-Length'
112
- expect(saved_headers).not_to include 'Connection'
82
+ it 'preserves ERB in the request params' do
83
+ generated_request = subject['request']
84
+ expect(generated_request['params']['apikey']).to eq("<%= ENV['MY_API_KEY'] %>")
113
85
  end
114
86
 
115
87
  it 'normalizes the request method' do
@@ -122,17 +94,6 @@ module Pacto
122
94
  expect(generated_response['status']).to eq(response_adapter.status)
123
95
  end
124
96
 
125
- it 'keeps important response headers' do
126
- saved_headers = subject['response']['headers']
127
- expect(saved_headers.keys).to include 'Content-Type'
128
- end
129
-
130
- it 'filters informational response headers' do
131
- saved_headers = subject['response']['headers']
132
- expect(saved_headers).not_to include 'Content-Length'
133
- expect(saved_headers).not_to include 'Via'
134
- end
135
-
136
97
  it 'generates pretty JSON' do
137
98
  expect(raw_contract).to eq(pretty(subject))
138
99
  end
@@ -31,7 +31,7 @@ module Pacto
31
31
  EOF
32
32
  end
33
33
 
34
- let(:invalid_contract) do
34
+ let(:partial_contract) do
35
35
  <<-EOF
36
36
  {
37
37
  "request": {
@@ -47,22 +47,62 @@ module Pacto
47
47
  EOF
48
48
  end
49
49
 
50
+ let(:invalid_contract) do
51
+ <<-EOF
52
+ {
53
+ "request": {
54
+ "method": "GET",
55
+ "path": "/hello_world",
56
+ "headers": {
57
+ "Accept": "application/json"
58
+ },
59
+ "params": {}
60
+ },
61
+
62
+ "response": {
63
+ "status": 200,
64
+ "headers": {
65
+ "Content-Type": "application/json"
66
+ },
67
+ "body": {
68
+ "description": "A simple response",
69
+ "required": {},
70
+ "type": "object",
71
+ "properties": {
72
+ "message": {
73
+ "type": "string"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ EOF
80
+ end
81
+
50
82
  subject(:schema) { MetaSchema.new }
51
83
 
52
84
  describe 'when validating a contract against the master schema' do
53
85
  context 'with a valid contract structure' do
54
86
  it 'does not raise any exceptions' do
55
- expect {
87
+ expect do
56
88
  schema.validate(valid_contract)
57
- }.to_not raise_error(Exception)
89
+ end.to_not raise_error(Exception)
90
+ end
91
+ end
92
+
93
+ context 'with an partial contract structure' do
94
+ it 'raises InvalidContract exception' do
95
+ expect do
96
+ schema.validate(invalid_contract)
97
+ end.to raise_error(InvalidContract)
58
98
  end
59
99
  end
60
100
 
61
- context 'with an invalid contract structure' do
101
+ context 'with an invalid contract' do
62
102
  it 'raises InvalidContract exception' do
63
- expect {
103
+ expect do
64
104
  schema.validate(invalid_contract)
65
- }.to raise_error(InvalidContract)
105
+ end.to raise_error(InvalidContract)
66
106
  end
67
107
  end
68
108
  end
@@ -1,5 +1,6 @@
1
- describe Pacto do
1
+ require 'spec_helper'
2
2
 
3
+ describe Pacto do
3
4
  around(:each) do |example|
4
5
  $stdout = StringIO.new
5
6
  example.run
@@ -19,7 +20,7 @@ describe Pacto do
19
20
  it 'displays a success message and return true' do
20
21
  mock_validation []
21
22
  success = Pacto.validate_contract 'my_contract.json'
22
- expect(output).to eq 'All contracts successfully meta-validated'
23
+ expect(output).to eq 'Validating my_contract.json'
23
24
  expect(success).to be_true
24
25
  end
25
26
  end
@@ -28,7 +29,7 @@ describe Pacto do
28
29
  it 'displays one error messages and return false' do
29
30
  mock_validation ['Error 1']
30
31
  success = Pacto.validate_contract 'my_contract.json'
31
- expect(output).to match /error/
32
+ expect(output).to match(/error/)
32
33
  expect(success).to be_false
33
34
  end
34
35
 
@@ -40,21 +41,22 @@ describe Pacto do
40
41
  end
41
42
  end
42
43
 
43
- describe '.build_from_file' do
44
- let(:path) { 'contract/path' }
45
- let(:host) { 'http://localhost' }
46
- let(:file_pre_processor) { double('file_pre_processor') }
47
- let(:instantiated_contract) { double(:instantiated_contract) }
44
+ describe 'loading contracts' do
45
+ let(:contracts_path) { 'path/to/dir' }
46
+ let(:host) { 'localhost' }
47
+ let(:contract1) { double }
48
+ let(:contract2) { double }
49
+ let(:factory) { double(:factory) }
48
50
 
49
- it 'delegates to ContractFactory' do
50
- Pacto::ContractFactory.should_receive(:build_from_file).with(path, host, file_pre_processor)
51
- described_class.build_from_file(path, host, file_pre_processor)
51
+ before do
52
+ allow(Pacto::ContractFactory).to receive(:new).and_return(factory)
52
53
  end
53
54
 
54
- it 'returns whatever the factory returns' do
55
- Pacto::ContractFactory.stub(:build_from_file => instantiated_contract)
56
- expect(described_class.build_from_file(path, host, file_pre_processor)).to eq instantiated_contract
55
+ it 'instantiates a contract list' do
56
+ allow(Pacto::ContractFiles).to receive(:for).with(contracts_path).and_return { %w{file1 file2} }
57
+ allow(factory).to receive(:build).with(%w{file1 file2}, host).and_return { [contract1, contract2] }
58
+ expect(Pacto::ContractList).to receive(:new).with([contract1, contract2])
59
+ Pacto.load_contracts(contracts_path, host)
57
60
  end
58
61
  end
59
-
60
62
  end