diff --git a/lib/pact/provider/pact_spec_runner.rb b/lib/pact/provider/pact_spec_runner.rb index e05387a0..0dad092f 100644 --- a/lib/pact/provider/pact_spec_runner.rb +++ b/lib/pact/provider/pact_spec_runner.rb @@ -12,6 +12,7 @@ require_relative 'rspec' +require 'pact/provider/rspec/json_formatter' module Pact module Provider diff --git a/lib/pact/provider/rspec/json_formatter.rb b/lib/pact/provider/rspec/json_formatter.rb new file mode 100644 index 00000000..3260f3ab --- /dev/null +++ b/lib/pact/provider/rspec/json_formatter.rb @@ -0,0 +1,86 @@ +require 'rspec/core/formatters/json_formatter' + +module Pact + module Provider + module RSpec + class JsonFormatter < ::RSpec::Core::Formatters::JsonFormatter + ::RSpec::Core::Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close + + def dump_summary(summary) + super(create_custom_summary(summary)) + output_hash[:summary][:notices] = pact_broker_notices(summary) + end + + def format_example(example) + { + :id => example.id, + :description => example.description, + :full_description => example.full_description, + :status => calculate_status(example), + :file_path => example.metadata[:file_path], + :line_number => example.metadata[:line_number], + :run_time => example.execution_result.run_time, + :mismatches => extract_differences(example) + } + end + + def stop(notification) + output_hash[:examples] = notification.examples.map do |example| + format_example(example).tap do |hash| + e = example.exception + # No point providing a backtrace for a mismatch, too much noise + if e && ! e.is_a?(::RSpec::Expectations::ExpectationNotMetError) + hash[:exception] = { + :class => e.class.name, + :message => e.message, + :backtrace => e.backtrace, + } + end + end + end + end + + def calculate_status(example) + if example.execution_result.status == :failed && example.metadata[:pact_ignore_failures] + 'pending' + else + example.execution_result.status.to_s + end + end + + # There will most likely be only one pact associated with this RSpec execution, because + # the most likely user of this formatter is the Go implementation that parses the JSON + # and builds Go tests from them. + # If the JSON formatter is used by someone else and they have multiple pacts, all the notices + # for the pacts will be mushed together in one collection, so it will be hard to know which notice + # belongs to which pact. + def pact_broker_notices(summary) + pact_uris(summary).collect{ |pact_uri| pact_uri.metadata[:notices] }.compact.flatten + end + + def pact_uris(summary) + summary.examples.collect(&:metadata).collect{ |metadata| metadata[:pact_uri] }.uniq + end + + def create_custom_summary(summary) + ::RSpec::Core::Notifications::SummaryNotification.new( + summary.duration, + summary.examples, + summary.examples.select{ | example | example.execution_result.status == :failed && !example.metadata[:pact_ignore_failures] }, + summary.examples.select{ | example | example.execution_result.status == :failed && example.metadata[:pact_ignore_failures] }, + summary.load_time, + summary.errors_outside_of_examples_count + ) + end + + def extract_differences(example) + if example.metadata[:pact_diff] + Pact::Matchers::ExtractDiffMessages.call(example.metadata[:pact_diff]).to_a + else + [] + end + end + end + end + end +end