Class: Cucumber::Formatter::SlimJSON
- Inherits:
-
Object
- Object
- Cucumber::Formatter::SlimJSON
- Includes:
- Console, FileUtils, Io
- Defined in:
- lib/cukable/slim_json_formatter.rb
Overview
FitNesse SliM JSON output formatter for Cucumber
Instance Method Summary (collapse)
-
- (Object) after_background(background)
Called after a
Background:block. -
- (Object) after_examples(examples)
Called after an
Examples:section. -
- (Object) after_feature(feature)
Called after each
.featureis run. -
- (Object) after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
Called after a step has executed, and we have a result.
-
- (Object) after_table_row(table_row)
Called after a table row is done being read.
-
- (Object) background_name(keyword, name, file_colon_line, source_indent)
Called when a
Background:line is read. -
- (Object) backtrace(exception)
Return an exception message and backtrace.
-
- (Object) before_background(background)
Called before a
Background:block. -
- (Object) before_examples(examples)
Called before an
Examples:section in a Scenario Outline. -
- (Object) before_feature(feature)
Called before each
.featureis run. -
- (Object) before_multiline_arg(multiline_arg)
Start a new multiline arg (such as a table or Py-string).
-
- (Object) before_step(step)
Called after a step has been executed, but before any output from that step has been done.
-
- (Object) before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
Called before any output from a step result.
-
- (Object) before_table_row(table_row)
Called before a table row is read.
-
- (Object) examples_name(keyword, name)
Called when the
Examples:line is read. -
- (Object) feature_name(keyword, name)
Called when
Feature:is read. -
- (SlimJSON) initialize(step_mother, path_or_io, options)
constructor
Create a new SlimJSON formatter, with the provided
path_or_io(as given by the--outoption) and any additional options passed to cucumber. -
- (Object) py_string(string)
Called when a multi-line string argument is read.
-
- (Object) sanitize(text)
Return
textwith any HTML-specific characters sanitized. -
- (Object) scenario_name(keyword, name, file_colon_line, source_indent)
Called when
Scenario:is read. -
- (Object) section_message(keyword, name, file_colon_line = '')
Return a string suitable for use as a section heading for "Feature:", "Scenario:" or "Scenario Outline:" output rows.
-
- (Object) source_message(file_colon_line)
Return a string for outputting the source filename and line number.
-
- (Object) status_map(status)
Map Cucumber status strings to FitNesse status strings.
-
- (Object) table_cell_value(value, status)
Called when a table cell value is read.
-
- (Object) tag_name(tag_name)
Called when a tag name is found.
Constructor Details
- (SlimJSON) initialize(step_mother, path_or_io, options)
Create a new SlimJSON formatter, with the provided path_or_io (as
given by the --out option) and any additional options passed to
cucumber.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/cukable/slim_json_formatter.rb', line 20
def initialize(step_mother, path_or_io, options)
@step_mother = step_mother
# Output directory
@out_dir = path_or_io
ensure_dir(@out_dir, "FitNesse")
# There should be no IO until we get a feature, and
# create the output directory in before_feature
@io = nil
# Cache of data lines to write
@data = []
# Multi-line output (must be cached and printed after the step that
# precedes it)
@multiline = []
# Expected/actual, to support table diffs
@expected_row = []
@actual_row = []
# Not in background until we actually find one
@in_background = false
end
|
Instance Method Details
- (Object) after_background(background)
Called after a Background: block.
93 94 95 |
# File 'lib/cukable/slim_json_formatter.rb', line 93
def after_background(background)
@in_background = false
end
|
- (Object) after_examples(examples)
Called after an Examples: section. Outputs anything accumulated in
@multiline, and empties it.
202 203 204 205 206 207 208 |
# File 'lib/cukable/slim_json_formatter.rb', line 202
def after_examples(examples)
# Output any multiline args that followed this step
@multiline.each do |row|
@data << row
end
@multiline = []
end
|
- (Object) after_feature(feature)
Called after each .feature is run. Write all @data to the JSON
file, then closes the output file.
58 59 60 61 62 |
# File 'lib/cukable/slim_json_formatter.rb', line 58
def after_feature(feature)
@io.puts JSON.pretty_generate(@data)
@io.flush
@io.close
end
|
- (Object) after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
Called after a step has executed, and we have a result. Generates a
single row of output in @data, including the status of the completed
step, along with one row for each line accumulated in a multi-line
argument (@multiline) if any were provided. Resets @multiline when
done.
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/cukable/slim_json_formatter.rb', line 267
def after_step_result(keyword, step_match, multiline_arg, status,
exception, source_indent, background)
return if @hide_this_step
# One-line message to print
message = ''
# A bit of a hack here to support Scenario Outlines
# Apparently, at the time of calling after_step_result, a StepMatch in
# a Scenario Outline has a `name` attribute (and no arguments to
# format, because they don't get pattern-matched until the Examples:
# section that fills them in), whereas a StepMatch in a normal scenario
# has no value set for its `name` attribute, and *does* have arguments
# to format. This behavior is exploited here for the sake of replacing
# the `<...>` angle brackets that appear in Scenario Outline steps.
#
# In other words, if `step_match` has a `name`, assume it's in a
# Scenario Outline, and replace the angle brackets (so the bracketed
# parameter can be displayed in an HTML page)
if step_match.name
step_name = keyword + step_match.name.gsub('<', '<').gsub('>', '>')
# Otherwise, wrap the arguments in bold tags
else
step_name = keyword + step_match.format_args("<b>%s</b>")
end
# Output the step name with appropriate colorization
stat = status_map(status)
message = "#{stat}:#{step_name}"
# Add the source file and line number where this step was defined
message += source_message(step_match.file_colon_line)
# Include additional info for undefined and failed steps
if status == :undefined
message += "<br/>(Undefined Step)"
elsif status == :failed && exception
message += backtrace(exception)
end
# Output the final message for this step
@data << [message]
# Output any multiline args that followed this step
@multiline.each do |row|
@data << row
end
@multiline = []
end
|
- (Object) after_table_row(table_row)
Called after a table row is done being read. Appends @table_row
to @multiline, which will be output in after_step_result.
There is some special handling here for handling table diffs; when doing a table diff, and a row doesn't match, two rows are generated. These need to be merged into a single row in the JSON output, to maintain the 1:1 mapping between FitNesse table and the returned results.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/cukable/slim_json_formatter.rb', line 129
def after_table_row(table_row)
return if @hide_this_step
# If we have an @expected_row and @actual_row at this point,
# merge them into a single row and append to @multiline_arg
if !@expected_row.empty? && !@actual_row.empty?
cell_diff = []
@expected_row.zip(@actual_row) do |expect, actual|
expect.gsub!(/^ignore:/, '')
actual.gsub!(/^error:/, '')
# If we got what we wanted in this cell, consider it passed
if actual == expect
cell_diff << "pass:#{actual}"
# Otherwise, show expected vs. actual as a failure
else
cell_diff << "fail:Expected: '#{expect}'<br/>Actual: '#{actual}'"
end
end
@multiline << ["report: "] + cell_diff
# Reset for upcoming rows
@expected_row = []
@actual_row = []
end
# Row with all cells having status == :comment (ignore)?
# This row was part of a table diff, and contains the values
# that were expected to be in the row.
if @table_row.all? { |cell| cell =~ /^ignore:/ }
@expected_row = @table_row
# Row with all cells having status == :undefined (error)?
# This row was part of a table diff, and contains the values
# that actually appeared in the row.
elsif @table_row.all? { |cell| cell =~ /^error:/ }
@actual_row = @table_row
# For any other row, append to multiline normally
else
# If an exception occurred in a table row, put the exception
# message in the first cell (which is normally empty). This
# allows us to show the exception without adding extra rows
# (which messes up the original table's formatting)
if table_row.exception
@multiline << ["fail:#{backtrace(table_row.exception)}"] + @table_row
# Otherwise, output an empty report: cell in the first column
else
@multiline << ["report: "] + @table_row
end
end
end
|
- (Object) background_name(keyword, name, file_colon_line, source_indent)
Called when a Background: line is read. Generates a single row of
output in @data with the Background: line.
87 88 89 |
# File 'lib/cukable/slim_json_formatter.rb', line 87
def background_name(keyword, name, file_colon_line, source_indent)
@data << [section_message(keyword, name, file_colon_line)]
end
|
- (Object) backtrace(exception)
Return an exception message and backtrace
355 356 357 358 359 360 361 |
# File 'lib/cukable/slim_json_formatter.rb', line 355
def backtrace(exception)
message = "<br/>" + sanitize(exception.message) + "<br/>"
message += exception.backtrace.collect { |line|
sanitize(line)
}.join("<br/>")
return message
end
|
- (Object) before_background(background)
Called before a Background: block.
80 81 82 |
# File 'lib/cukable/slim_json_formatter.rb', line 80
def before_background(background)
@in_background = true
end
|
- (Object) before_examples(examples)
Called before an Examples: section in a Scenario Outline. An
Examples: table works similarly to a multiline argument, except there
is no associated step to output them. The after_table_row method
will still accumulate the table rows, but we need to rely on
after_examples to output them. Thus, we will be accumulating these
rows in the multi-purpose @multiline variable, initialized here.
188 189 190 |
# File 'lib/cukable/slim_json_formatter.rb', line 188
def before_examples(examples)
@multiline = []
end
|
- (Object) before_feature(feature)
Called before each .feature is run. Creates a new output file for the
results in @out_dir, and empties @data.
47 48 49 50 51 52 53 |
# File 'lib/cukable/slim_json_formatter.rb', line 47
def before_feature(feature)
file = File.join(@out_dir, "#{feature.file}.json")
dir = File.dirname(file)
mkdir_p(dir) unless File.directory?(dir)
@io = ensure_file(file, "FitNesse")
@data = []
end
|
- (Object) before_multiline_arg(multiline_arg)
Start a new multiline arg (such as a table or Py-string). Initializes
@multiline and related arrays.
100 101 102 103 104 |
# File 'lib/cukable/slim_json_formatter.rb', line 100
def before_multiline_arg(multiline_arg)
@multiline = []
@expected_row = []
@actual_row = []
end
|
- (Object) before_step(step)
Called after a step has been executed, but before any output from that step has been done.
213 214 215 |
# File 'lib/cukable/slim_json_formatter.rb', line 213
def before_step(step)
@current_step = step
end
|
- (Object) before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
Called before any output from a step result. To avoid redundant output,
we want to show the results of Background steps only once, within the
Background section (unless a background step somehow failed when it
was executed at the top of a Scenario). Here, background is true if
the step was defined in the Background section, and @in_background
is true if we are actually inside the Background section during
execution. In short, if a step was defined in the Background section,
but we are not within the Background section now, we want to hide
the step's output.
252 253 254 255 256 257 258 259 |
# File 'lib/cukable/slim_json_formatter.rb', line 252
def before_step_result(keyword, step_match, multiline_arg, status,
exception, source_indent, background)
if status != :failed && @in_background ^ background
@hide_this_step = true
else
@hide_this_step = false
end
end
|
- (Object) before_table_row(table_row)
Called before a table row is read. Starts a new @table_row.
108 109 110 |
# File 'lib/cukable/slim_json_formatter.rb', line 108
def before_table_row(table_row)
@table_row = []
end
|
- (Object) examples_name(keyword, name)
Called when the Examples: line is read. Outputs the Examples: line
to @data.
195 196 197 |
# File 'lib/cukable/slim_json_formatter.rb', line 195
def examples_name(keyword, name)
@data << ["report:#{keyword}: #{name}"]
end
|
- (Object) feature_name(keyword, name)
Called when Feature: <name> is read. Generates a single row of output
in @data with the feature name.
67 68 69 |
# File 'lib/cukable/slim_json_formatter.rb', line 67
def feature_name(keyword, name)
@data << [section_message(keyword, name)]
end
|
- (Object) py_string(string)
Called when a multi-line string argument is read. Generates a row of
output for each line in the multi-line string (including the """
opening and closing lines), colored based on the status of the current
step. The output is accumulated in @multiline, for output in
after_step_result.
223 224 225 226 227 228 229 230 231 |
# File 'lib/cukable/slim_json_formatter.rb', line 223
def py_string(string)
return if @hide_this_step
status = status_map(@current_step.status)
@multiline << [status + ':"""']
string.split("\n").each do |line|
@multiline << ["#{status}:#{line}"]
end
@multiline << [status + ':"""']
end
|
- (Object) sanitize(text)
Return text with any HTML-specific characters sanitized
336 337 338 |
# File 'lib/cukable/slim_json_formatter.rb', line 336
def sanitize(text)
text.gsub('<', '<').gsub('>', '>')
end
|
- (Object) scenario_name(keyword, name, file_colon_line, source_indent)
Called when Scenario: <name> is read. Generates a single row of
output in @data with the scenario name.
74 75 76 |
# File 'lib/cukable/slim_json_formatter.rb', line 74
def scenario_name(keyword, name, file_colon_line, source_indent)
@data << [section_message(keyword, name, file_colon_line)]
end
|
- (Object) section_message(keyword, name, file_colon_line = '')
Return a string suitable for use as a section heading for "Feature:", "Scenario:" or "Scenario Outline:" output rows.
349 350 351 |
# File 'lib/cukable/slim_json_formatter.rb', line 349
def section_message(keyword, name, file_colon_line='')
"report:#{keyword}: #{name}" + source_message(file_colon_line)
end
|
- (Object) source_message(file_colon_line)
Return a string for outputting the source filename and line number
342 343 344 |
# File 'lib/cukable/slim_json_formatter.rb', line 342
def source_message(file_colon_line)
return " <span class=\"source_file\">" + file_colon_line + '</span>'
end
|
- (Object) status_map(status)
Map Cucumber status strings to FitNesse status strings
322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/cukable/slim_json_formatter.rb', line 322
def status_map(status)
case status
when nil then 'pass'
when :passed then 'pass'
when :failed then 'fail'
when :undefined then 'error'
when :skipped then 'ignore'
when :comment then 'ignore'
else 'pass'
end
end
|
- (Object) table_cell_value(value, status)
Called when a table cell value is read. Appends to @table_row.
114 115 116 117 118 |
# File 'lib/cukable/slim_json_formatter.rb', line 114
def table_cell_value(value, status)
return if @hide_this_step
stat = status_map(status)
@table_row << "#{stat}:#{value}"
end
|
- (Object) tag_name(tag_name)
Called when a tag name is found. Generates a single row of output in
@data with the tag name. (Note that this will only work properly if
there is only one tag per line; otherwise, too many lines may be
output.)
238 239 240 |
# File 'lib/cukable/slim_json_formatter.rb', line 238
def tag_name(tag_name)
@data << ["ignore:#{tag_name}"]
end
|