Class: Ctrf::CucumberFormatter

Inherits:
Object
  • Object
show all
Includes:
Cucumber::Formatter::Io
Defined in:
lib/ctrf/cucumber_formatter.rb

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ CucumberFormatter

Returns a new instance of CucumberFormatter.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ctrf/cucumber_formatter.rb', line 11

def initialize(config)
  @io = ensure_io(config.out_stream, config.error_stream)
  @ast_lookup = Cucumber::Formatter::AstLookup.new(config)
  @tests = {}
  begin
    @bc = Rails::ActiveSupport::BacktraceCleaner.new
  rescue StandardError
    @bc = nil
  end

  @run_start = Time.now.to_i
  config.on_event :test_case_started, &method(:on_test_case_started)
  config.on_event :test_case_finished, &method(:on_test_case_finished)
  config.on_event :test_step_started, &method(:on_test_step_started)
  config.on_event :test_step_finished, &method(:on_test_step_finished)
  config.on_event :test_run_finished, &method(:on_test_run_finished)
end

Instance Method Details

#attach(src, mime_type, _filename) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/ctrf/cucumber_formatter.rb', line 105

def attach(src, mime_type, _filename)
  if mime_type == 'text/x.cucumber.log+plain'
    test_step_output << src
    return
  end
  if mime_type =~ /;base64$/
    mime_type = mime_type[0..-8]
    data = src
  else
    data = encode64(src)
  end
  test_step_embeddings << { mime_type: mime_type, data: data }
end

#format_exception(exception) ⇒ Object



127
128
129
130
# File 'lib/ctrf/cucumber_formatter.rb', line 127

def format_exception(exception)
  backtrace = @bc.nil? ? exception.backtrace : @bc.clean(exception.backtrace)
  (["#{exception.message} (#{exception.class})"] + backtrace[..10]).join("\n")
end

#get_backtrace_object(result) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/ctrf/cucumber_formatter.rb', line 119

def get_backtrace_object(result)
  if result.failed?
    result.exception
  elsif result.backtrace
    result
  end
end

#on_test_case_finished(event) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ctrf/cucumber_formatter.rb', line 52

def on_test_case_finished(event)
  test = @tests[event.test_case.hash]
  test[:duration] = event.result.duration.nanoseconds / 1_000_000

  # Pull existing status, if any
  existing_status = test[:status]
  test[:status] = sym_to_status(event.result.to_sym)
  test[:rawStatus] = event.result.to_sym

  # If this is a retry, we failed last time and passed this time, it's flaky
  test[:flaky] = !existing_status.nil? && existing_status = 'failed' && test[:status] == 'passed'
  unless existing_status.nil?
    test[:retries] = 0 unless test.key?(:retries)
    test[:retries] += 1
  end

  # Attach error information, if any
  test[:message] = event.result.to_message.message
  exception = get_backtrace_object(event.result) unless event.result.passed?

  # If this wasn't the first run, move the trace to extra
  if test.key?(:trace)
    test[:extra][:previous_traces] = [] unless test[:extra].key?(:previous_traces)
    test[:extra][:previous_traces].push(test[:trace])
    test.delete(:trace)
  end
  test[:trace] = format_exception(exception) if exception
end

#on_test_case_started(event) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/ctrf/cucumber_formatter.rb', line 29

def on_test_case_started(event)
  # Set up the object for use if it doesn't exist already
  # It might, if retries
  return if @tests.key?(event.test_case.hash)

  @tests[event.test_case.hash] = {
    name: event.test_case.name,
    suite: event.test_case.location.file,
    filePath: event.test_case.location.to_s,
    extra: {
      hash: event.test_case.hash
    }
  }
end

#on_test_run_finished(_event) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ctrf/cucumber_formatter.rb', line 81

def on_test_run_finished(_event)
  # Build the final result object
  result = {
    results: {
      tool: {
        name: 'Cucumber-Ruby'
      },
      summary: {
        tests: @tests.count,
        passed: @tests.values.select { |test| test[:status] == 'passed' }.count,
        failed: @tests.values.select { |test| test[:status] == 'failed' }.count,
        pending: @tests.values.select { |test| test[:status] == 'pending' }.count,
        skipped: @tests.values.select { |test| test[:status] == 'skipped' }.count,
        other: @tests.values.select { |test| test[:status] == 'other' }.count,
        start: @run_start,
        stop: Time.now.to_i
      },
      tests: @tests.values
    }
  }

  @io.write(JSON.pretty_generate(result))
end

#on_test_step_finished(event) ⇒ Object



48
49
50
# File 'lib/ctrf/cucumber_formatter.rb', line 48

def on_test_step_finished(event)
  # Don't care about steps rn
end

#on_test_step_started(event) ⇒ Object



44
45
46
# File 'lib/ctrf/cucumber_formatter.rb', line 44

def on_test_step_started(event)
  # Don't care about steps rn
end

#sym_to_status(sym) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/ctrf/cucumber_formatter.rb', line 132

def sym_to_status(sym)
  case sym
  when :failed
    'failed'
  when :passed
    'passed'
  when :skipped
    'skipped'
  when :pending
    'pending'
  else
    'other'
  end
end