cucumber 3.2.0 → 4.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +166 -19
- data/CONTRIBUTING.md +2 -18
- data/README.md +4 -5
- data/bin/cucumber +1 -1
- data/lib/autotest/cucumber_mixin.rb +34 -39
- data/lib/cucumber/cli/configuration.rb +5 -5
- data/lib/cucumber/cli/main.rb +12 -12
- data/lib/cucumber/cli/options.rb +62 -71
- data/lib/cucumber/cli/profile_loader.rb +49 -26
- data/lib/cucumber/configuration.rb +31 -23
- data/lib/cucumber/constantize.rb +2 -5
- data/lib/cucumber/deprecate.rb +31 -7
- data/lib/cucumber/errors.rb +5 -7
- data/lib/cucumber/events/envelope.rb +9 -0
- data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
- data/lib/cucumber/events/hook_test_step_created.rb +13 -0
- data/lib/cucumber/events/step_activated.rb +2 -1
- data/lib/cucumber/events/test_case_created.rb +13 -0
- data/lib/cucumber/events/test_case_ready.rb +12 -0
- data/lib/cucumber/events/test_step_created.rb +13 -0
- data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
- data/lib/cucumber/events.rb +13 -6
- data/lib/cucumber/file_specs.rb +6 -6
- data/lib/cucumber/filters/activate_steps.rb +5 -3
- data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
- data/lib/cucumber/filters/prepare_world.rb +5 -9
- data/lib/cucumber/filters/quit.rb +1 -3
- data/lib/cucumber/filters/tag_limits/verifier.rb +2 -4
- data/lib/cucumber/filters.rb +1 -0
- data/lib/cucumber/formatter/ansicolor.rb +40 -45
- data/lib/cucumber/formatter/ast_lookup.rb +165 -0
- data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
- data/lib/cucumber/formatter/console.rb +58 -66
- data/lib/cucumber/formatter/console_counts.rb +4 -9
- data/lib/cucumber/formatter/console_issues.rb +6 -3
- data/lib/cucumber/formatter/duration.rb +1 -1
- data/lib/cucumber/formatter/duration_extractor.rb +3 -1
- data/lib/cucumber/formatter/errors.rb +6 -0
- data/lib/cucumber/formatter/fanout.rb +2 -0
- data/lib/cucumber/formatter/html.rb +11 -598
- data/lib/cucumber/formatter/http_io.rb +1 -1
- data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
- data/lib/cucumber/formatter/interceptor.rb +8 -28
- data/lib/cucumber/formatter/io.rb +1 -1
- data/lib/cucumber/formatter/json.rb +101 -115
- data/lib/cucumber/formatter/junit.rb +56 -56
- data/lib/cucumber/formatter/message.rb +22 -0
- data/lib/cucumber/formatter/message_builder.rb +255 -0
- data/lib/cucumber/formatter/pretty.rb +359 -153
- data/lib/cucumber/formatter/progress.rb +30 -32
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
- data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
- data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
- data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
- data/lib/cucumber/formatter/rerun.rb +22 -4
- data/lib/cucumber/formatter/stepdefs.rb +1 -2
- data/lib/cucumber/formatter/steps.rb +2 -3
- data/lib/cucumber/formatter/summary.rb +16 -8
- data/lib/cucumber/formatter/unicode.rb +15 -17
- data/lib/cucumber/formatter/usage.rb +11 -10
- data/lib/cucumber/gherkin/data_table_parser.rb +17 -6
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +13 -17
- data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
- data/lib/cucumber/gherkin/steps_parser.rb +17 -8
- data/lib/cucumber/glue/dsl.rb +1 -1
- data/lib/cucumber/glue/hook.rb +34 -11
- data/lib/cucumber/glue/invoke_in_world.rb +13 -18
- data/lib/cucumber/glue/proto_world.rb +42 -33
- data/lib/cucumber/glue/registry_and_more.rb +42 -12
- data/lib/cucumber/glue/snippet.rb +23 -22
- data/lib/cucumber/glue/step_definition.rb +42 -19
- data/lib/cucumber/glue/world_factory.rb +1 -1
- data/lib/cucumber/hooks.rb +11 -11
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +1 -1
- data/lib/cucumber/multiline_argument/data_table.rb +97 -64
- data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
- data/lib/cucumber/multiline_argument.rb +4 -6
- data/lib/cucumber/platform.rb +3 -3
- data/lib/cucumber/rake/task.rb +16 -16
- data/lib/cucumber/rspec/disable_option_parser.rb +9 -8
- data/lib/cucumber/running_test_case.rb +2 -53
- data/lib/cucumber/runtime/after_hooks.rb +8 -4
- data/lib/cucumber/runtime/before_hooks.rb +8 -4
- data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
- data/lib/cucumber/runtime/step_hooks.rb +3 -2
- data/lib/cucumber/runtime/support_code.rb +13 -15
- data/lib/cucumber/runtime/user_interface.rb +6 -16
- data/lib/cucumber/runtime.rb +54 -58
- data/lib/cucumber/step_definition_light.rb +4 -3
- data/lib/cucumber/step_definitions.rb +2 -2
- data/lib/cucumber/step_match.rb +12 -11
- data/lib/cucumber/step_match_search.rb +2 -1
- data/lib/cucumber/term/ansicolor.rb +9 -9
- data/lib/cucumber/version +1 -1
- data/lib/cucumber.rb +1 -1
- metadata +221 -77
- data/lib/cucumber/formatter/cucumber.css +0 -286
- data/lib/cucumber/formatter/cucumber.sass +0 -247
- data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
- data/lib/cucumber/formatter/html_builder.rb +0 -121
- data/lib/cucumber/formatter/inline-js.js +0 -30
- data/lib/cucumber/formatter/jquery-min.js +0 -154
- data/lib/cucumber/formatter/json_pretty.rb +0 -11
- data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
- data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
- data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
- data/lib/cucumber/step_argument.rb +0 -25
@@ -1,13 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cucumber/core/report/summary'
|
4
3
|
require 'cucumber/formatter/backtrace_filter'
|
5
4
|
require 'cucumber/formatter/console'
|
6
5
|
require 'cucumber/formatter/console_counts'
|
7
6
|
require 'cucumber/formatter/console_issues'
|
8
7
|
require 'cucumber/formatter/io'
|
9
8
|
require 'cucumber/formatter/duration_extractor'
|
10
|
-
require 'cucumber/formatter/
|
9
|
+
require 'cucumber/formatter/ast_lookup'
|
11
10
|
|
12
11
|
module Cucumber
|
13
12
|
module Formatter
|
@@ -15,56 +14,58 @@ module Cucumber
|
|
15
14
|
class Progress
|
16
15
|
include Console
|
17
16
|
include Io
|
18
|
-
attr_reader :
|
19
|
-
|
17
|
+
attr_reader :config, :current_feature_uri
|
18
|
+
private :config, :current_feature_uri
|
20
19
|
|
21
20
|
def initialize(config)
|
22
|
-
@config
|
23
|
-
@
|
21
|
+
@config = config
|
22
|
+
@io = ensure_io(config.out_stream)
|
24
23
|
@snippets_input = []
|
24
|
+
@undefined_parameter_types = []
|
25
25
|
@total_duration = 0
|
26
|
-
@summary = Cucumber::Core::Report::Summary.new(config.event_bus)
|
27
26
|
@matches = {}
|
28
27
|
@pending_step_matches = []
|
29
28
|
@failed_results = []
|
30
|
-
@failed_test_cases = []
|
31
29
|
@passed_test_cases = []
|
30
|
+
@current_feature_uri = ''
|
31
|
+
@gherkin_documents = {}
|
32
|
+
@ast_lookup = AstLookup.new(config)
|
32
33
|
@counts = ConsoleCounts.new(config)
|
33
|
-
@issues = ConsoleIssues.new(config)
|
34
|
+
@issues = ConsoleIssues.new(config, @ast_lookup)
|
34
35
|
config.on_event :step_activated, &method(:on_step_activated)
|
35
36
|
config.on_event :test_case_started, &method(:on_test_case_started)
|
36
37
|
config.on_event :test_step_finished, &method(:on_test_step_finished)
|
37
38
|
config.on_event :test_case_finished, &method(:on_test_case_finished)
|
38
39
|
config.on_event :test_run_finished, &method(:on_test_run_finished)
|
40
|
+
config.on_event :undefined_parameter_type, &method(:collect_undefined_parameter_type_names)
|
39
41
|
end
|
40
42
|
|
41
43
|
def on_step_activated(event)
|
42
|
-
@matches[event.test_step.
|
44
|
+
@matches[event.test_step.to_s] = event.step_match
|
43
45
|
end
|
44
46
|
|
45
|
-
def on_test_case_started(
|
47
|
+
def on_test_case_started(event)
|
46
48
|
unless @profile_information_printed
|
47
49
|
do_print_profile_information(config.profiles) unless config.skip_profile_information? || config.profiles.nil? || config.profiles.empty?
|
48
50
|
@profile_information_printed = true
|
49
51
|
end
|
50
|
-
@
|
52
|
+
@current_feature_uri = event.test_case.location.file
|
51
53
|
end
|
52
54
|
|
53
55
|
def on_test_step_finished(event)
|
54
56
|
test_step = event.test_step
|
55
57
|
result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
|
56
|
-
progress(result.to_sym) if !
|
58
|
+
progress(result.to_sym) if !test_step.hook? || result.failed?
|
57
59
|
|
58
|
-
return if
|
59
|
-
collect_snippet_data(test_step, result
|
60
|
-
@pending_step_matches << @matches[test_step.
|
60
|
+
return if test_step.hook?
|
61
|
+
collect_snippet_data(test_step, @ast_lookup) if result.undefined?
|
62
|
+
@pending_step_matches << @matches[test_step.to_s] if result.pending?
|
61
63
|
@failed_results << result if result.failed?
|
62
64
|
end
|
63
65
|
|
64
66
|
def on_test_case_finished(event)
|
65
67
|
test_case = event.test_case
|
66
68
|
result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
|
67
|
-
@failed_test_cases << test_case if result.failed?
|
68
69
|
@passed_test_cases << test_case if result.passed?
|
69
70
|
@total_duration += DurationExtractor.new(result).result_duration
|
70
71
|
end
|
@@ -77,28 +78,25 @@ module Cucumber
|
|
77
78
|
|
78
79
|
private
|
79
80
|
|
81
|
+
def gherkin_document
|
82
|
+
@ast_lookup.gherkin_document(current_feature_uri)
|
83
|
+
end
|
84
|
+
|
80
85
|
def print_summary
|
81
86
|
print_elements(@pending_step_matches, :pending, 'steps')
|
82
87
|
print_elements(@failed_results, :failed, 'steps')
|
83
88
|
print_statistics(@total_duration, @config, @counts, @issues)
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
do_print_snippets(snippet_text_proc) if config.snippets? && summary.test_steps.total(:undefined) > 0
|
88
|
-
return unless config.wip?
|
89
|
-
messages = @passed_test_cases.map do |test_case|
|
90
|
-
linebreaks("#{test_case.location.on_line(test_case.location.line)}:in `#{test_case.name}'", ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
|
91
|
-
end
|
92
|
-
do_print_passing_wip(messages)
|
89
|
+
print_snippets(config.to_hash)
|
90
|
+
print_passing_wip(config, @passed_test_cases, @ast_lookup)
|
93
91
|
end
|
94
92
|
|
95
93
|
CHARS = {
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
100
|
-
:
|
101
|
-
}
|
94
|
+
passed: '.',
|
95
|
+
failed: 'F',
|
96
|
+
undefined: 'U',
|
97
|
+
pending: 'P',
|
98
|
+
skipped: '-'
|
99
|
+
}.freeze
|
102
100
|
|
103
101
|
def progress(status)
|
104
102
|
char = CHARS[status]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'cucumber/formatter/errors'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Formatter
|
5
|
+
module Query
|
6
|
+
class HookByTestStep
|
7
|
+
def initialize(config)
|
8
|
+
@hook_id_by_test_step_id = {}
|
9
|
+
|
10
|
+
config.on_event :test_step_created, &method(:on_test_step_created)
|
11
|
+
config.on_event :hook_test_step_created, &method(:on_hook_test_step_created)
|
12
|
+
end
|
13
|
+
|
14
|
+
def hook_id(test_step)
|
15
|
+
return @hook_id_by_test_step_id[test_step.id] if @hook_id_by_test_step_id.key?(test_step.id)
|
16
|
+
raise TestStepUnknownError, "No hook found for #{test_step.id} }. Known: #{@hook_id_by_test_step_id.keys}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def on_test_step_created(event)
|
22
|
+
@hook_id_by_test_step_id[event.test_step.id] = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_hook_test_step_created(event)
|
26
|
+
@hook_id_by_test_step_id[event.test_step.id] = event.hook.id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'cucumber/formatter/errors'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Formatter
|
5
|
+
module Query
|
6
|
+
class PickleByTest
|
7
|
+
def initialize(config)
|
8
|
+
@pickle_id_by_test_case_id = {}
|
9
|
+
config.on_event :test_case_created, &method(:on_test_case_created)
|
10
|
+
end
|
11
|
+
|
12
|
+
def pickle_id(test_case)
|
13
|
+
return @pickle_id_by_test_case_id[test_case.id] if @pickle_id_by_test_case_id.key?(test_case.id)
|
14
|
+
|
15
|
+
raise TestCaseUnknownError, "No pickle found for #{test_case.id} }. Known: #{@pickle_id_by_test_case_id.keys}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def on_test_case_created(event)
|
21
|
+
@pickle_id_by_test_case_id[event.test_case.id] = event.pickle.id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'cucumber/formatter/errors'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Formatter
|
5
|
+
module Query
|
6
|
+
class PickleStepByTestStep
|
7
|
+
def initialize(config)
|
8
|
+
@pickle_id_step_by_test_step_id = {}
|
9
|
+
config.on_event :test_step_created, &method(:on_test_step_created)
|
10
|
+
end
|
11
|
+
|
12
|
+
def pickle_step_id(test_step)
|
13
|
+
return @pickle_id_step_by_test_step_id[test_step.id] if @pickle_id_step_by_test_step_id.key?(test_step.id)
|
14
|
+
|
15
|
+
raise TestStepUnknownError, "No pickle step found for #{test_step.id} }. Known: #{@pickle_id_step_by_test_step_id.keys}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def on_test_step_created(event)
|
21
|
+
@pickle_id_step_by_test_step_id[event.test_step.id] = event.pickle_step.id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'cucumber/formatter/errors'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Formatter
|
5
|
+
module Query
|
6
|
+
class StepDefinitionsByTestStep
|
7
|
+
def initialize(config)
|
8
|
+
@step_definition_ids_by_test_step_id = {}
|
9
|
+
@step_match_arguments_by_test_step_id = {}
|
10
|
+
|
11
|
+
config.on_event :test_step_created, &method(:on_test_step_created)
|
12
|
+
config.on_event :step_activated, &method(:on_step_activated)
|
13
|
+
end
|
14
|
+
|
15
|
+
def step_definition_ids(test_step)
|
16
|
+
return @step_definition_ids_by_test_step_id[test_step.id] if @step_definition_ids_by_test_step_id.key?(test_step.id)
|
17
|
+
|
18
|
+
raise TestStepUnknownError, "No step definition found for #{test_step.id} }. Known: #{@step_definition_ids_by_test_step_id.keys}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def step_match_arguments(test_step)
|
22
|
+
return @step_match_arguments_by_test_step_id[test_step.id] if @step_match_arguments_by_test_step_id.key?(test_step.id)
|
23
|
+
|
24
|
+
raise TestStepUnknownError, "No step match arguments found for #{test_step.id} }. Known: #{@step_match_arguments_by_test_step_id.keys}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def on_test_step_created(event)
|
30
|
+
@step_definition_ids_by_test_step_id[event.test_step.id] = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_step_activated(event)
|
34
|
+
@step_definition_ids_by_test_step_id[event.test_step.id] << event.step_match.step_definition.id
|
35
|
+
@step_match_arguments_by_test_step_id[event.test_step.id] = event.step_match.step_arguments
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'cucumber/formatter/errors'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Formatter
|
5
|
+
module Query
|
6
|
+
class TestCaseStartedByTestCase
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
config.on_event :test_case_created, &method(:on_test_case_created)
|
10
|
+
config.on_event :test_case_started, &method(:on_test_case_started)
|
11
|
+
|
12
|
+
@attempts_by_test_case_id = {}
|
13
|
+
@test_case_started_id_by_test_case_id = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def attempt_by_test_case(test_case)
|
17
|
+
raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@attempts_by_test_case_id.keys}" unless @attempts_by_test_case_id.key?(test_case.id)
|
18
|
+
@attempts_by_test_case_id[test_case.id]
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_case_started_id_by_test_case(test_case)
|
22
|
+
raise TestCaseUnknownError, "No test case found for #{test_case.id} }. Known: #{@test_case_started_id_by_test_case_id.keys}" unless @test_case_started_id_by_test_case_id.key?(test_case.id)
|
23
|
+
@test_case_started_id_by_test_case_id[test_case.id]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def on_test_case_created(event)
|
29
|
+
@attempts_by_test_case_id[event.test_case.id] = 0
|
30
|
+
@test_case_started_id_by_test_case_id[event.test_case.id] = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_test_case_started(event)
|
34
|
+
@attempts_by_test_case_id[event.test_case.id] += 1
|
35
|
+
@test_case_started_id_by_test_case_id[event.test_case.id] = @config.id_generator.new_id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -7,17 +7,29 @@ module Cucumber
|
|
7
7
|
class Rerun
|
8
8
|
include Formatter::Io
|
9
9
|
|
10
|
-
def initialize(config)
|
10
|
+
def initialize(config) # rubocop:disable Metrics/PerceivedComplexity
|
11
11
|
@io = ensure_io(config.out_stream)
|
12
12
|
@config = config
|
13
13
|
@failures = {}
|
14
14
|
config.on_event :test_case_finished do |event|
|
15
15
|
test_case, result = *event.attributes
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
if @config.strict.strict?(:flaky)
|
17
|
+
next if result.ok?(@config.strict)
|
18
|
+
add_to_failures(test_case)
|
19
|
+
else
|
20
|
+
unless @latest_failed_test_case.nil?
|
21
|
+
if @latest_failed_test_case != test_case
|
22
|
+
add_to_failures(@latest_failed_test_case)
|
23
|
+
@latest_failed_test_case = nil
|
24
|
+
elsif result.ok?(@config.strict)
|
25
|
+
@latest_failed_test_case = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@latest_failed_test_case = test_case unless result.ok?(@config.strict)
|
29
|
+
end
|
19
30
|
end
|
20
31
|
config.on_event :test_run_finished do
|
32
|
+
add_to_failures(@latest_failed_test_case) unless @latest_failed_test_case.nil?
|
21
33
|
next if @failures.empty?
|
22
34
|
@io.print file_failures.join("\n")
|
23
35
|
end
|
@@ -28,6 +40,12 @@ module Cucumber
|
|
28
40
|
def file_failures
|
29
41
|
@failures.map { |file, lines| [file, lines].join(':') }
|
30
42
|
end
|
43
|
+
|
44
|
+
def add_to_failures(test_case)
|
45
|
+
location = test_case.location
|
46
|
+
@failures[location.file] ||= []
|
47
|
+
@failures[location.file] << location.lines.max unless @failures[location.file].include?(location.lines.max)
|
48
|
+
end
|
31
49
|
end
|
32
50
|
end
|
33
51
|
end
|
@@ -35,15 +35,14 @@ module Cucumber
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def collect_steps(runtime)
|
38
|
-
runtime.step_definitions.
|
38
|
+
runtime.step_definitions.each_with_object({}) do |step_definition, step_definitions|
|
39
39
|
step_definitions[step_definition.file] ||= []
|
40
40
|
step_definitions[step_definition.file] << [step_definition.file_colon_line, step_definition.regexp_source]
|
41
|
-
step_definitions
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
44
|
def source_indent(sources)
|
46
|
-
sources.map { |
|
45
|
+
sources.map { |_file_colon_line, regexp| regexp.size }.max + 1
|
47
46
|
end
|
48
47
|
end
|
49
48
|
end
|
@@ -5,6 +5,7 @@ require 'cucumber/formatter/console'
|
|
5
5
|
require 'cucumber/formatter/console_counts'
|
6
6
|
require 'cucumber/formatter/console_issues'
|
7
7
|
require 'cucumber/core/test/result'
|
8
|
+
require 'cucumber/formatter/ast_lookup'
|
8
9
|
|
9
10
|
module Cucumber
|
10
11
|
module Formatter
|
@@ -14,9 +15,11 @@ module Cucumber
|
|
14
15
|
include Console
|
15
16
|
|
16
17
|
def initialize(config)
|
17
|
-
@config
|
18
|
+
@config = config
|
19
|
+
@io = ensure_io(config.out_stream)
|
20
|
+
@ast_lookup = AstLookup.new(config)
|
18
21
|
@counts = ConsoleCounts.new(@config)
|
19
|
-
@issues = ConsoleIssues.new(@config)
|
22
|
+
@issues = ConsoleIssues.new(@config, @ast_lookup)
|
20
23
|
@start_time = Time.now
|
21
24
|
|
22
25
|
@config.on_event :test_case_started do |event|
|
@@ -28,7 +31,7 @@ module Cucumber
|
|
28
31
|
print_result event.result
|
29
32
|
end
|
30
33
|
|
31
|
-
@config.on_event :test_run_finished do |
|
34
|
+
@config.on_event :test_run_finished do |_event|
|
32
35
|
duration = Time.now - @start_time
|
33
36
|
@io.puts
|
34
37
|
print_statistics(duration, @config, @counts, @issues)
|
@@ -37,12 +40,17 @@ module Cucumber
|
|
37
40
|
|
38
41
|
private
|
39
42
|
|
43
|
+
def gherkin_document(uri)
|
44
|
+
@ast_lookup.gherkin_document(uri)
|
45
|
+
end
|
46
|
+
|
40
47
|
def print_feature(test_case)
|
41
|
-
|
42
|
-
return if @
|
43
|
-
|
44
|
-
@io.puts
|
45
|
-
@
|
48
|
+
uri = test_case.location.file
|
49
|
+
return if @current_feature_uri == uri
|
50
|
+
feature_name = gherkin_document(uri).feature.name
|
51
|
+
@io.puts unless @current_feature_uri.nil?
|
52
|
+
@io.puts feature_name
|
53
|
+
@current_feature_uri = uri
|
46
54
|
end
|
47
55
|
|
48
56
|
def print_test_case(test_case)
|
@@ -9,39 +9,37 @@ if Cucumber::WINDOWS
|
|
9
9
|
if ENV['CUCUMBER_OUTPUT_ENCODING']
|
10
10
|
Cucumber::CODEPAGE = ENV['CUCUMBER_OUTPUT_ENCODING']
|
11
11
|
elsif `cmd /c chcp` =~ /(\d+)/
|
12
|
-
if [
|
13
|
-
Cucumber::CODEPAGE = 'UTF-8'
|
12
|
+
if [65_000, 65_001].include? Regexp.last_match(1).to_i
|
13
|
+
Cucumber::CODEPAGE = 'UTF-8'.freeze
|
14
14
|
ENV['ANSICON_API'] = 'ruby'
|
15
15
|
else
|
16
|
-
Cucumber::CODEPAGE = "cp#{
|
16
|
+
Cucumber::CODEPAGE = "cp#{Regexp.last_match(1).to_i}".freeze
|
17
17
|
end
|
18
18
|
else
|
19
|
-
Cucumber::CODEPAGE = 'cp1252'
|
19
|
+
Cucumber::CODEPAGE = 'cp1252'.freeze
|
20
20
|
STDERR.puts("WARNING: Couldn't detect your output codepage. Assuming it is 1252. You may have to chcp 1252 or SET CUCUMBER_OUTPUT_ENCODING=cp1252.")
|
21
21
|
end
|
22
22
|
|
23
23
|
module Cucumber
|
24
24
|
# @private
|
25
25
|
module WindowsOutput
|
26
|
-
def self.extended(
|
27
|
-
|
28
|
-
def cucumber_preprocess_output(*
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
a
|
34
|
-
end
|
26
|
+
def self.extended(output)
|
27
|
+
output.instance_eval do
|
28
|
+
def cucumber_preprocess_output(*out)
|
29
|
+
out.map { |arg| arg.to_s.encode(Encoding.default_external) }
|
30
|
+
rescue Encoding::UndefinedConversionError => e
|
31
|
+
STDERR.cucumber_puts("WARNING: #{e.message}")
|
32
|
+
out
|
35
33
|
end
|
36
34
|
|
37
35
|
alias cucumber_print print
|
38
|
-
def print(*
|
39
|
-
cucumber_print(*cucumber_preprocess_output(*
|
36
|
+
def print(*out)
|
37
|
+
cucumber_print(*cucumber_preprocess_output(*out))
|
40
38
|
end
|
41
39
|
|
42
40
|
alias cucumber_puts puts
|
43
|
-
def puts(*
|
44
|
-
cucumber_puts(*cucumber_preprocess_output(*
|
41
|
+
def puts(*out)
|
42
|
+
cucumber_puts(*cucumber_preprocess_output(*out))
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -17,7 +17,7 @@ module Cucumber
|
|
17
17
|
@matches = {}
|
18
18
|
config.on_event :step_activated do |event|
|
19
19
|
test_step, step_match = *event.attributes
|
20
|
-
@matches[test_step.
|
20
|
+
@matches[test_step.to_s] = step_match
|
21
21
|
end
|
22
22
|
config.on_event :step_definition_registered, &method(:on_step_definition_registered)
|
23
23
|
end
|
@@ -28,25 +28,26 @@ module Cucumber
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def on_step_match(event)
|
31
|
-
@matches[event.test_step.
|
31
|
+
@matches[event.test_step.to_s] = event.step_match
|
32
32
|
super
|
33
33
|
end
|
34
34
|
|
35
35
|
def on_test_step_finished(event)
|
36
|
-
return if
|
36
|
+
return if event.test_step.hook?
|
37
37
|
|
38
38
|
test_step = event.test_step
|
39
39
|
result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
|
40
|
-
step_match = @matches[test_step.
|
40
|
+
step_match = @matches[test_step.to_s]
|
41
41
|
|
42
42
|
unless step_match.nil?
|
43
43
|
step_definition = step_match.step_definition
|
44
44
|
stepdef_key = StepDefKey.new(step_definition.expression.to_s, step_definition.location)
|
45
45
|
unless @stepdef_to_match[stepdef_key].map { |key| key[:location] }.include? test_step.location
|
46
46
|
duration = DurationExtractor.new(result).result_duration
|
47
|
+
keyword = @ast_lookup.step_source(test_step).step.keyword
|
47
48
|
|
48
49
|
@stepdef_to_match[stepdef_key] << {
|
49
|
-
keyword:
|
50
|
+
keyword: keyword,
|
50
51
|
step_match: step_match,
|
51
52
|
status: result.to_sym,
|
52
53
|
location: test_step.location,
|
@@ -64,9 +65,9 @@ module Cucumber
|
|
64
65
|
aggregate_info
|
65
66
|
|
66
67
|
keys = if config.dry_run?
|
67
|
-
@stepdef_to_match.keys.
|
68
|
+
@stepdef_to_match.keys.sort_by(&:regexp_source)
|
68
69
|
else
|
69
|
-
@stepdef_to_match.keys.
|
70
|
+
@stepdef_to_match.keys.sort_by(&:mean_duration).reverse
|
70
71
|
end
|
71
72
|
|
72
73
|
keys.each do |stepdef_key|
|
@@ -83,7 +84,7 @@ module Cucumber
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def print_step_definition(stepdef_key)
|
86
|
-
@io.print format_string(format('
|
87
|
+
@io.print format_string(format('%<duration>.7f', duration: stepdef_key.mean_duration), :skipped) + ' ' unless config.dry_run?
|
87
88
|
@io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
|
88
89
|
if config.source?
|
89
90
|
indent = max_length - stepdef_key.regexp_source.unpack('U*').length
|
@@ -96,7 +97,7 @@ module Cucumber
|
|
96
97
|
def print_steps(stepdef_key)
|
97
98
|
@stepdef_to_match[stepdef_key].each do |step|
|
98
99
|
@io.print ' '
|
99
|
-
@io.print format_string(format('
|
100
|
+
@io.print format_string(format('%<duration>.7f', duration: step[:duration]), :skipped) + ' ' unless config.dry_run?
|
100
101
|
@io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
|
101
102
|
if config.source?
|
102
103
|
indent = max_length - (step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length)
|
@@ -135,7 +136,7 @@ module Cucumber
|
|
135
136
|
end
|
136
137
|
|
137
138
|
def worst_status(statuses)
|
138
|
-
[
|
139
|
+
%i[passed undefined pending skipped failed].find do |status|
|
139
140
|
statuses.include?(status)
|
140
141
|
end
|
141
142
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'gherkin
|
4
|
-
require 'gherkin/parser'
|
3
|
+
require 'gherkin'
|
5
4
|
require 'gherkin/dialect'
|
6
5
|
|
7
6
|
module Cucumber
|
@@ -12,15 +11,27 @@ module Cucumber
|
|
12
11
|
end
|
13
12
|
|
14
13
|
def parse(text)
|
15
|
-
|
16
|
-
|
17
|
-
gherkin_document = parser.parse(token_scanner)
|
14
|
+
gherkin_document = nil
|
15
|
+
messages = ::Gherkin.from_source('dummy', feature_header + text, gherkin_options)
|
18
16
|
|
19
|
-
|
17
|
+
messages.each do |message|
|
18
|
+
gherkin_document = message.gherkin_document.to_hash unless message.gherkin_document.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
return if gherkin_document.nil?
|
22
|
+
gherkin_document[:feature][:children][0][:scenario][:steps][0][:data_table][:rows].each do |row|
|
20
23
|
@builder.row(row[:cells].map { |cell| cell[:value] })
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
27
|
+
def gherkin_options
|
28
|
+
{
|
29
|
+
include_source: false,
|
30
|
+
include_gherkin_document: true,
|
31
|
+
include_pickles: false
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
24
35
|
def feature_header
|
25
36
|
dialect = ::Gherkin::Dialect.for('en')
|
26
37
|
%(#{dialect.feature_keywords[0]}:
|
@@ -51,23 +51,21 @@ module Cucumber
|
|
51
51
|
'white' => "\e[37m",
|
52
52
|
'grey' => "\e[90m",
|
53
53
|
'bold' => "\e[1m"
|
54
|
-
}
|
54
|
+
}.freeze
|
55
55
|
|
56
56
|
ALIASES = Hash.new do |h, k|
|
57
|
-
if k.to_s =~ /(.*)_arg/
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
'tag' => 'cyan'
|
70
|
-
})
|
57
|
+
h[Regexp.last_match(1)] + ',bold' if k.to_s =~ /(.*)_arg/
|
58
|
+
end.merge(
|
59
|
+
'undefined' => 'yellow',
|
60
|
+
'pending' => 'yellow',
|
61
|
+
'executing' => 'grey',
|
62
|
+
'failed' => 'red',
|
63
|
+
'passed' => 'green',
|
64
|
+
'outline' => 'cyan',
|
65
|
+
'skipped' => 'cyan',
|
66
|
+
'comments' => 'grey',
|
67
|
+
'tag' => 'cyan'
|
68
|
+
)
|
71
69
|
|
72
70
|
if ENV['GHERKIN_COLORS'] # Example: export GHERKIN_COLORS="passed=red:failed=yellow"
|
73
71
|
ENV['GHERKIN_COLORS'].split(':').each do |pair|
|
@@ -93,8 +91,6 @@ module Cucumber
|
|
93
91
|
def up(n)
|
94
92
|
"\e[#{n}A"
|
95
93
|
end
|
96
|
-
|
97
|
-
extend self
|
98
94
|
end
|
99
95
|
end
|
100
96
|
end
|
@@ -10,8 +10,8 @@ module Cucumber
|
|
10
10
|
# * \ becomes \\
|
11
11
|
#
|
12
12
|
# This is used in the pretty formatter.
|
13
|
-
def escape_cell(
|
14
|
-
|
13
|
+
def escape_cell(sym)
|
14
|
+
sym.gsub(/\\(?!\|)/, '\\\\\\\\').gsub(/\n/, '\\n').gsub(/\|/, '\\|')
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|