diff --git a/.gitignore b/.gitignore index faf42af..c3011d3 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ tmp tags pacto.log .polytrix/ +.ruby-gemset +.ruby-version diff --git a/lib/pacto/consumer/faraday_driver.rb b/lib/pacto/consumer/faraday_driver.rb index 2d5b06d..e62d86e 100644 --- a/lib/pacto/consumer/faraday_driver.rb +++ b/lib/pacto/consumer/faraday_driver.rb @@ -11,7 +11,7 @@ def execute(req) response = conn.send(req.method) do |faraday_request| # faraday_request.url = req.uri faraday_request.headers = req.headers - faraday_request.body = req.body + faraday_request.body = (req.body.is_a?(String) ? req.body : req.body.to_json) end faraday_to_pacto_response response diff --git a/lib/pacto/native_contract_factory.rb b/lib/pacto/native_contract_factory.rb index f23d6a5..96095af 100644 --- a/lib/pacto/native_contract_factory.rb +++ b/lib/pacto/native_contract_factory.rb @@ -1,3 +1,5 @@ +require 'erb' + module Pacto # Builds {Pacto::Contract} instances from Pacto's native Contract format. class NativeContractFactory @@ -8,14 +10,14 @@ def initialize(options = {}) end def build_from_file(contract_path, host) - contract_definition = File.read(contract_path) - definition = JSON.parse(contract_definition) + definition = parse_json(contract_path) schema.validate definition - definition['request'].merge!('host' => host) + body_to_schema(definition, 'request', contract_path) body_to_schema(definition, 'response', contract_path) method_to_http_method(definition, contract_path) - request = RequestClause.new(definition['request']) + + request = RequestClause.new(definition['request'].merge('host' => host)) response = ResponseClause.new(definition['response']) Contract.new(request: request, response: response, file: contract_path, name: definition['name'], examples: definition['examples']) end @@ -24,7 +26,7 @@ def files_for(contracts_dir) full_path = Pathname.new(contracts_dir).realpath if full_path.directory? - all_json_files = "#{full_path}/**/*.json" + all_json_files = "#{full_path}/**/*{.json,.json.erb}" Dir.glob(all_json_files).map do |f| Pathname.new(f) end @@ -35,6 +37,12 @@ def files_for(contracts_dir) private + def parse_json(path) + contents = File.read(path) + contents = ERB.new(contents).result if path.to_s.end_with? '.erb' + JSON.parse(contents) + end + def body_to_schema(definition, section, file) schema = definition[section].delete 'body' return nil unless schema diff --git a/lib/pacto/stubs/webmock_adapter.rb b/lib/pacto/stubs/webmock_adapter.rb index e2547d8..375ee11 100644 --- a/lib/pacto/stubs/webmock_adapter.rb +++ b/lib/pacto/stubs/webmock_adapter.rb @@ -54,7 +54,9 @@ def stub_request!(contract) uri_pattern = UriPattern.for(request_clause) stub = WebMock.stub_request(request_clause.http_method, uri_pattern) - stub.request_pattern.with(strict_details(request_clause)) if Pacto.configuration.strict_matchers + if Pacto.configuration.strict_matchers && strict_details(request_clause).any? + stub.request_pattern.with(strict_details(request_clause)) + end stub.to_return do |request| pacto_request = Pacto::Adapters::WebMock::PactoRequest.new request diff --git a/spec/fixtures/contracts/contract.json.erb b/spec/fixtures/contracts/contract.json.erb new file mode 100644 index 0000000..d54ce73 --- /dev/null +++ b/spec/fixtures/contracts/contract.json.erb @@ -0,0 +1,38 @@ +{ + "request": { + "http_method": "GET", + "path": "/hello_world", + "headers": { + "Accept": "application/json" + }, + "params": {} + }, + + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json" + }, + "schema": { + "description": "A simple response", + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + }, + + "examples": { + "default": { + "request": {}, + "response": { + "body": { + "message": "<%= "foo#{2+2}" %>", + "count": <%= 2+2 %> + } + } + } + } +} diff --git a/spec/unit/pacto/native_contract_factory_spec.rb b/spec/unit/pacto/native_contract_factory_spec.rb index ed7be9b..da07469 100644 --- a/spec/unit/pacto/native_contract_factory_spec.rb +++ b/spec/unit/pacto/native_contract_factory_spec.rb @@ -13,6 +13,24 @@ module Pacto expect(contract).to be_a(Contract) end + context 'contract template ends with .erb' do + let(:contract_path) { File.join(contracts_path, "#{contract_name}.json.erb") } + + it 'builds the contract' do + contract = contract_factory.build_from_file(contract_path, host) + expect(contract).to be_a(Contract) + end + end + + context 'contract template does not end with .erb' do + let(:contract_name) { 'templating_contract' } + + it 'builds the contract' do + contract = contract_factory.build_from_file(contract_path, host) + expect(contract).to be_a(Contract) + end + end + context 'deprecated contracts' do let(:contracts_path) { %w(spec fixtures deprecated_contracts) } let(:contract_name) { 'deprecated_contract' } @@ -21,5 +39,21 @@ module Pacto expect(contract).to be_a(Contract) end end + + describe '#files_for' do + context 'given directory' do + let(:contract_path) { File.join(contracts_path) } + + it 'includes .json files' do + files = contract_factory.files_for(contract_path).collect { |f| f.basename.to_s } + expect(files).to include('contract.json') + end + + it 'includes .json.erb files' do + files = contract_factory.files_for(contract_path).collect { |f| f.basename.to_s } + expect(files).to include('contract.json.erb') + end + end + end end end diff --git a/spec/unit/pacto/stubs/webmock_adapter_spec.rb b/spec/unit/pacto/stubs/webmock_adapter_spec.rb index e5a1ae7..9e1d158 100644 --- a/spec/unit/pacto/stubs/webmock_adapter_spec.rb +++ b/spec/unit/pacto/stubs/webmock_adapter_spec.rb @@ -142,9 +142,7 @@ module Stubs end it 'uses WebMock to stub the request' do - expect(request_pattern).to receive(:with). - with({}). - and_return(stubbed_request) + expect(request_pattern).to_not receive(:with) adapter.stub_request! contract end end