qat-cucumber 6.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 +7 -0
- data/LICENSE +674 -0
- data/bin/qat +5 -0
- data/lib/qat/cli/generator/project.rb +32 -0
- data/lib/qat/cli/generator.rb +48 -0
- data/lib/qat/cli/main.rb +102 -0
- data/lib/qat/cli/plugins/core.rb +19 -0
- data/lib/qat/cli.rb +52 -0
- data/lib/qat/cucumber/core_ext/formatter/html.rb +48 -0
- data/lib/qat/cucumber/core_ext/formatter/junit.rb +57 -0
- data/lib/qat/cucumber/core_ext/result.rb +16 -0
- data/lib/qat/cucumber/core_ext.rb +3 -0
- data/lib/qat/cucumber/hooks/scenario.rb +76 -0
- data/lib/qat/cucumber/hooks.rb +72 -0
- data/lib/qat/cucumber/logger.rb +49 -0
- data/lib/qat/cucumber/time.rb +55 -0
- data/lib/qat/cucumber/version.rb +15 -0
- data/lib/qat/cucumber/world.rb +40 -0
- data/lib/qat/cucumber.rb +76 -0
- data/lib/qat/formatter/console.rb +101 -0
- data/lib/qat/formatter/dashboard.rb +84 -0
- data/lib/qat/formatter/loggable/mdc.rb +74 -0
- data/lib/qat/formatter/loggable/scenario_info.rb +40 -0
- data/lib/qat/formatter/loggable.rb +92 -0
- data/lib/qat/formatter/scenario/name.rb +47 -0
- data/lib/qat/formatter/tags.rb +81 -0
- data/lib/qat/formatter/test_ids.rb +93 -0
- data/lib/qat/jenkins.rb +43 -0
- data/lib/qat/project/Gemfile +13 -0
- data/lib/qat/project/Rakefile +3 -0
- data/lib/qat/project/config/cucumber.yml +13 -0
- data/lib/qat/project/config/default.yml +1 -0
- data/lib/qat/project/config/env-dummy/hosts.yml +9 -0
- data/lib/qat/project/config/env-dummy/jenkins.yml +7 -0
- data/lib/qat/project/config/env-dummy/logger.yml +23 -0
- data/lib/qat/project/config/env-dummy/time.yml +11 -0
- data/lib/qat/project/features/feature.feature +45 -0
- data/lib/qat/project/features/step_definitions/steps.rb +4 -0
- data/lib/qat/project/features/support/env.rb +6 -0
- data/lib/qat/project/features/support/hooks.rb +32 -0
- data/lib/qat/tasks/list.rb +50 -0
- data/lib/qat/tasks/steps.rb +20 -0
- data/lib/qat/tasks/tags/test_ids/helpers.rb +105 -0
- data/lib/qat/tasks/tags/test_ids/report.rb +41 -0
- data/lib/qat/tasks/tags/test_ids.rb +60 -0
- data/lib/qat/tasks/tags.rb +2 -0
- data/lib/qat/tasks/test.rb +35 -0
- data/lib/qat/tasks.rb +8 -0
- metadata +193 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'minitest'
|
3
|
+
require 'cucumber'
|
4
|
+
require_relative 'version'
|
5
|
+
require 'qat/logger'
|
6
|
+
|
7
|
+
module QAT
|
8
|
+
module Cucumber
|
9
|
+
#Cucumber World utility. Will be automatically included in the World object when this file is required.
|
10
|
+
#Includes MiniTest and a Logger utility.
|
11
|
+
#In order to define the Logger channel, a World Class should be defined by the user.
|
12
|
+
#Should be required in the env.rb file.
|
13
|
+
module World
|
14
|
+
include QAT::Logger
|
15
|
+
include Minitest::Assertions
|
16
|
+
|
17
|
+
attr_accessor :assertions
|
18
|
+
|
19
|
+
# @!attribute assertions
|
20
|
+
# @return [Integer] Counter of assertions for Minitest integration.
|
21
|
+
def assertions
|
22
|
+
@assertions ||= 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_id
|
26
|
+
QAT[:current_test_id]
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_run_id
|
30
|
+
QAT[:current_test_run_id]
|
31
|
+
end
|
32
|
+
|
33
|
+
def evidence_prefix
|
34
|
+
QAT[:current_test_run_id]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/lib/qat/cucumber.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'minitest'
|
3
|
+
require 'cucumber'
|
4
|
+
require_relative 'cucumber/version'
|
5
|
+
require_relative 'cucumber/core_ext'
|
6
|
+
require 'qat/logger'
|
7
|
+
require 'qat/core'
|
8
|
+
require 'qat/configuration'
|
9
|
+
require 'qat/time'
|
10
|
+
require_relative 'jenkins' if ENV['JENKINS_URL']
|
11
|
+
require_relative 'cucumber/logger'
|
12
|
+
require_relative 'cucumber/time'
|
13
|
+
|
14
|
+
require_relative 'cucumber/hooks'
|
15
|
+
require_relative 'cucumber/world'
|
16
|
+
World QAT::Cucumber::World
|
17
|
+
|
18
|
+
#QAT Module works as a namespace for all sub modules.
|
19
|
+
#Some singleton methods are also available, as defined by various sub classes.
|
20
|
+
#@since 0.1.0
|
21
|
+
module QAT
|
22
|
+
# Namespace for various helpers when running with cucumber.
|
23
|
+
#Just require 'qat/cucumber' to automatically integrate all the available helpers.
|
24
|
+
#
|
25
|
+
#@since 0.1.0
|
26
|
+
module Cucumber
|
27
|
+
include QAT::Logger
|
28
|
+
|
29
|
+
class << self
|
30
|
+
include QAT::Cucumber::Logger
|
31
|
+
include QAT::Cucumber::Time
|
32
|
+
|
33
|
+
# Launches the pre-test configurations and integrations
|
34
|
+
# This includes:
|
35
|
+
# - Time Synchronization between the host running tests
|
36
|
+
# and a target host (test environment?) if configured
|
37
|
+
# - Setups the Jenkins integration if running this CI Server
|
38
|
+
def launch!
|
39
|
+
current_configuration = QAT.configuration
|
40
|
+
|
41
|
+
raise EmptyConfiguration.new "No valid configuration exists to run tests!" unless current_configuration
|
42
|
+
raise InvalidConfiguration.new "No valid environment is defined, aborting test execution!" unless current_configuration.environment
|
43
|
+
|
44
|
+
config_logger(current_configuration)
|
45
|
+
|
46
|
+
time_sync if current_configuration[:time]
|
47
|
+
|
48
|
+
setup_jenkins((current_configuration)) if ENV['JENKINS_URL']
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Initializes the Jenkins configuration for test run
|
54
|
+
# @param configuration [Hash] configuration
|
55
|
+
def setup_jenkins(configuration)
|
56
|
+
jenkins_vars = configuration.dig(:jenkins, :env_vars)
|
57
|
+
|
58
|
+
if jenkins_vars
|
59
|
+
QAT::Jenkins.register_vars(jenkins_vars)
|
60
|
+
else
|
61
|
+
log.debug { "Configuring Jenkins with default options." }
|
62
|
+
QAT::Jenkins.register_vars
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# This class represents a empty configuration error when there is no configuration available
|
68
|
+
class EmptyConfiguration < StandardError
|
69
|
+
end
|
70
|
+
# This class represents a invalid configuration error when the configuration is not complete
|
71
|
+
class InvalidConfiguration < StandardError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
QAT::Cucumber.launch!
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'cucumber/formatter/console'
|
3
|
+
require 'cucumber/formatter/io'
|
4
|
+
require 'cucumber/gherkin/formatter/escaping'
|
5
|
+
require 'qat/logger'
|
6
|
+
require_relative 'loggable'
|
7
|
+
|
8
|
+
module QAT
|
9
|
+
module Formatter
|
10
|
+
# Formatter to print Feature, Scenario and Step information on the fly. Will use STDOUT by default or a specified
|
11
|
+
# logger configuration channel.
|
12
|
+
#@see QAT::Loggger
|
13
|
+
#@since 0.1.0
|
14
|
+
class Console
|
15
|
+
include ::FileUtils
|
16
|
+
include ::Cucumber::Formatter::Io
|
17
|
+
include ::Cucumber::Gherkin::Formatter::Escaping
|
18
|
+
include QAT::Formatter::Loggable
|
19
|
+
include QAT::Logger
|
20
|
+
|
21
|
+
#@api private
|
22
|
+
def initialize(_, path_or_io, options)
|
23
|
+
@options = options
|
24
|
+
|
25
|
+
check_outputter path_or_io unless options[:dry_run]
|
26
|
+
end
|
27
|
+
|
28
|
+
#@api private
|
29
|
+
def before_test_case test_case
|
30
|
+
return if @options[:dry_run]
|
31
|
+
|
32
|
+
unless @current_feature
|
33
|
+
@current_feature = test_case.source[0]
|
34
|
+
log.info { "Running #{@current_feature.keyword}: \"#{@current_feature.name}\"" }
|
35
|
+
mdc_before_feature! @current_feature.name
|
36
|
+
end
|
37
|
+
|
38
|
+
@current_scenario = test_case.source[1]
|
39
|
+
end
|
40
|
+
|
41
|
+
#@api private
|
42
|
+
def after_feature *_
|
43
|
+
return if @options[:dry_run]
|
44
|
+
|
45
|
+
log.info { "Finished #{@current_feature.keyword}: \"#{@current_feature.name}\"" }
|
46
|
+
@current_feature = nil
|
47
|
+
mdc_after_feature!
|
48
|
+
end
|
49
|
+
|
50
|
+
#@api private
|
51
|
+
def after_test_case step, result
|
52
|
+
return if @options[:dry_run]
|
53
|
+
|
54
|
+
log.error { result.exception } if result.failed?
|
55
|
+
|
56
|
+
log.info { "Finished #{@current_scenario.keyword}: \"#{format_scenario_name step}\" - #{result.to_sym}\n" } if @current_scenario
|
57
|
+
end
|
58
|
+
|
59
|
+
#@api private
|
60
|
+
def before_test_step step
|
61
|
+
return if @options[:dry_run]
|
62
|
+
|
63
|
+
begin_test_step step do |type|
|
64
|
+
case type
|
65
|
+
when :after_step
|
66
|
+
log.info "Step Done!" if @step_running
|
67
|
+
when :before_scenario
|
68
|
+
log.info { "Running #{@current_scenario.keyword}: \"#{format_scenario_name step}\"" }
|
69
|
+
when :before_step
|
70
|
+
log.info "Step Done!\n" if @step_running
|
71
|
+
step_name = "#{step.source.last.keyword}#{step.name}"
|
72
|
+
log.info { "Step \"#{step_name}\"" }
|
73
|
+
mdc_add_step! step_name
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#@api private
|
79
|
+
def puts obj
|
80
|
+
return if @options[:dry_run]
|
81
|
+
|
82
|
+
log.debug { obj }
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def format_scenario_name step
|
87
|
+
return '' unless @current_scenario
|
88
|
+
outline_number, outline_example = nil, nil
|
89
|
+
scenario_name = if @current_scenario.is_a? ::Cucumber::Core::Ast::ScenarioOutline
|
90
|
+
outline_example = step.source[3].values
|
91
|
+
outline_number = calculate_outline_id(step)
|
92
|
+
"#{@current_scenario.name} ##{outline_number}"
|
93
|
+
else
|
94
|
+
@current_scenario.name
|
95
|
+
end
|
96
|
+
mdc_before_scenario! @current_scenario.name, tags_from_test_step(step), outline_number, outline_example
|
97
|
+
return scenario_name
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'cucumber/formatter/console'
|
3
|
+
require 'cucumber/formatter/io'
|
4
|
+
require 'cucumber/gherkin/formatter/escaping'
|
5
|
+
require 'qat/logger'
|
6
|
+
require_relative 'loggable'
|
7
|
+
|
8
|
+
module QAT
|
9
|
+
module Formatter
|
10
|
+
# Formatter to send error information to a Dashboard server. Output should be configured in the logger file.
|
11
|
+
#@see QAT::Loggger
|
12
|
+
#@since 0.1.0
|
13
|
+
class Dashboard
|
14
|
+
include ::FileUtils
|
15
|
+
include ::Cucumber::Formatter::Io
|
16
|
+
include ::Cucumber::Gherkin::Formatter::Escaping
|
17
|
+
include QAT::Formatter::Loggable
|
18
|
+
include QAT::Logger
|
19
|
+
|
20
|
+
#@api private
|
21
|
+
def initialize(_, path_or_io, options)
|
22
|
+
@options = options
|
23
|
+
|
24
|
+
ensure_outputter path_or_io unless options[:dry_run]
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
#@api private
|
29
|
+
def before_test_case test_case
|
30
|
+
return if @options[:dry_run]
|
31
|
+
|
32
|
+
unless @current_feature
|
33
|
+
@current_feature = test_case.source[0]
|
34
|
+
mdc_before_feature! @current_feature.name
|
35
|
+
end
|
36
|
+
|
37
|
+
@current_scenario = test_case.source[1]
|
38
|
+
end
|
39
|
+
|
40
|
+
#@api private
|
41
|
+
def after_feature *_
|
42
|
+
return if @options[:dry_run]
|
43
|
+
|
44
|
+
@current_feature = nil
|
45
|
+
mdc_after_feature!
|
46
|
+
end
|
47
|
+
|
48
|
+
#@api private
|
49
|
+
def after_test_case step, passed
|
50
|
+
return if @options[:dry_run]
|
51
|
+
|
52
|
+
if passed.respond_to? :exception
|
53
|
+
mdc_add_step! @step_name
|
54
|
+
mdc_add_status_failed!
|
55
|
+
log.error passed.exception
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#@api private
|
60
|
+
def before_test_step step
|
61
|
+
return if @options[:dry_run]
|
62
|
+
|
63
|
+
begin_test_step step do |type|
|
64
|
+
if type == :before_step
|
65
|
+
@step_name = "#{step.source.last.keyword}#{step.name}"
|
66
|
+
mdc_add_step! @step_name
|
67
|
+
elsif :before_scenario
|
68
|
+
outline_number, outline_example = nil, nil
|
69
|
+
if @current_scenario.is_a? ::Cucumber::Core::Ast::ScenarioOutline
|
70
|
+
outline_example = step.source[3].values
|
71
|
+
outline_number = calculate_outline_id(step)
|
72
|
+
end
|
73
|
+
mdc_before_scenario! @current_scenario.name, tags_from_test_step(step), outline_number, outline_example
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# #@api private
|
79
|
+
# def exception e, _
|
80
|
+
# log.error e
|
81
|
+
# end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'qat/logger'
|
2
|
+
require_relative 'scenario_info'
|
3
|
+
|
4
|
+
module QAT
|
5
|
+
module Formatter
|
6
|
+
module Loggable
|
7
|
+
#Helper module to manage loggable mdc information
|
8
|
+
#@since 2.0.2
|
9
|
+
module Mdc
|
10
|
+
include ScenarioInfo
|
11
|
+
|
12
|
+
#Set the MDC key 'feature' with the given value.
|
13
|
+
#@param feature_name [String] Name of the current feature
|
14
|
+
#@since 0.1.0
|
15
|
+
def mdc_before_feature!(feature_name)
|
16
|
+
Log4r::MDC.put 'feature', feature_name
|
17
|
+
end
|
18
|
+
|
19
|
+
#Remove the MDC key 'feature'.
|
20
|
+
#@since 0.1.0
|
21
|
+
def mdc_after_feature!
|
22
|
+
Log4r::MDC.remove 'feature'
|
23
|
+
end
|
24
|
+
|
25
|
+
#Set the MDC key 'scenario' with the given value.
|
26
|
+
#Optionally scenario outline data can also be provided
|
27
|
+
#@param scenario_name [String] Name of the current feature
|
28
|
+
#@param tags [Array<String>] List of tags
|
29
|
+
#@param outline_number [Integer] Number of the current scenario outline
|
30
|
+
#@param outline_example [Array<String>] Values of the current outline's example row
|
31
|
+
#@since 0.1.0
|
32
|
+
def mdc_before_scenario!(scenario_name, tags, outline_number = nil, outline_example = nil)
|
33
|
+
mdc_reset_scenario!
|
34
|
+
Log4r::MDC.put 'scenario', scenario_name
|
35
|
+
|
36
|
+
test_id = test_id(tags, outline_number)
|
37
|
+
Log4r::MDC.put 'test_id', test_id
|
38
|
+
loggable_tags = tags.reject { |tag| tag.match(/^\@test\#/) }
|
39
|
+
Log4r::MDC.put 'tags', loggable_tags
|
40
|
+
|
41
|
+
Log4r::MDC.put 'outline_number', outline_number if outline_number
|
42
|
+
Log4r::MDC.put 'outline_example', outline_example if outline_example
|
43
|
+
end
|
44
|
+
|
45
|
+
#Remove the MDC key 'scenario'. Other options set in #mdc_before_scenario! will also be unset.
|
46
|
+
#@since 0.1.0
|
47
|
+
def mdc_reset_scenario!
|
48
|
+
mdc_remove_step!
|
49
|
+
Log4r::MDC.remove 'scenario'
|
50
|
+
Log4r::MDC.remove 'tags'
|
51
|
+
Log4r::MDC.remove 'outline_number'
|
52
|
+
Log4r::MDC.remove 'outline_example'
|
53
|
+
end
|
54
|
+
|
55
|
+
#Set the MDC key 'step' with the given value.
|
56
|
+
#@param step_name [String] Name of the current step
|
57
|
+
#@since 0.1.0
|
58
|
+
def mdc_add_step!(step_name)
|
59
|
+
Log4r::MDC.put 'step', step_name
|
60
|
+
end
|
61
|
+
|
62
|
+
#Remove the MDC key 'step'.
|
63
|
+
#@since 0.1.0
|
64
|
+
def mdc_remove_step!
|
65
|
+
Log4r::MDC.remove 'step'
|
66
|
+
end
|
67
|
+
|
68
|
+
def mdc_add_status_failed!
|
69
|
+
Log4r::MDC.put 'status', 'failed'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'qat/logger'
|
2
|
+
|
3
|
+
module QAT
|
4
|
+
module Formatter
|
5
|
+
module Loggable
|
6
|
+
#Helper module to manage loggable scenario information
|
7
|
+
#@since 2.0.2
|
8
|
+
module ScenarioInfo
|
9
|
+
protected
|
10
|
+
|
11
|
+
def tags_from_test_step(step)
|
12
|
+
step.source.inject([]) do |sum, current_source|
|
13
|
+
sum << current_source.tags if current_source.respond_to? :tags
|
14
|
+
sum
|
15
|
+
end.flatten.map(&:name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_id(tags, outline_id)
|
19
|
+
tag = tags.select { |tag| tag.match /^\@test\#\d+$/ }.first
|
20
|
+
if tag
|
21
|
+
id = tag.gsub '@test#', 'test_'
|
22
|
+
id << ".#{outline_id}" if outline_id
|
23
|
+
id
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def calculate_outline_id(step)
|
30
|
+
source = step.source
|
31
|
+
tables = source[1].instance_exec { @examples_tables }
|
32
|
+
table_lines = tables.each.map { |line| line.example_rows.size }
|
33
|
+
table_num = tables.index source[2]
|
34
|
+
previous_outlines = table_lines[0...table_num].inject(0) { |sum, lines| sum += lines; sum }
|
35
|
+
"#{previous_outlines + source[3].number}".to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'qat/logger'
|
2
|
+
require_relative 'loggable/mdc'
|
3
|
+
|
4
|
+
module QAT
|
5
|
+
#Namespace for custom Cucumber formatters and helpers.
|
6
|
+
#@since 0.1.0
|
7
|
+
module Formatter
|
8
|
+
#Helper module to manage formatters based on QAT::Logger
|
9
|
+
#@since 0.1.0
|
10
|
+
module Loggable
|
11
|
+
include QAT::Logger
|
12
|
+
include Mdc
|
13
|
+
|
14
|
+
def check_outputter name
|
15
|
+
return if name.respond_to? :write #Is an IO
|
16
|
+
|
17
|
+
add_outputter_with name
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def ensure_outputter name
|
22
|
+
raise ArgumentError.new "No outputter configured for formatter #{self.class.name}" if name.respond_to? :write
|
23
|
+
|
24
|
+
add_outputter_with name
|
25
|
+
end
|
26
|
+
|
27
|
+
#Parses a test step and determines it's type: after step, before scenario or before step.
|
28
|
+
#Allows a block to be used to execute in the middle of the processing
|
29
|
+
#@param step [Cucumber::Core::Test::Step] Step to parse
|
30
|
+
#@yield [type] Block to execute in the middle of processing
|
31
|
+
#@yieldparam [Symbol] type Type of the test step
|
32
|
+
#@return [Symbol] type Type of the test step
|
33
|
+
#@since 0.1.0
|
34
|
+
def begin_test_step step
|
35
|
+
#World: step.location = /usr/local/rvm/gems/ruby-2.2.3/gems/cucumber-2.0.2/lib/cucumber/filters/prepare_world.rb:27
|
36
|
+
# step.name = "Before hook"
|
37
|
+
|
38
|
+
#Hooks: step.location = /home/mgomes/Projects/qat/src/qat/lib/qat/cucumber/hooks.rb:53
|
39
|
+
# step.name = "Before hook"
|
40
|
+
|
41
|
+
#Stepdef: step.location = features/formatter.feature:8
|
42
|
+
# step.name = step name
|
43
|
+
|
44
|
+
type = set_type(step)
|
45
|
+
|
46
|
+
yield type if block_given? and type
|
47
|
+
|
48
|
+
set_step_status(type)
|
49
|
+
|
50
|
+
type
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def add_outputter_with(name)
|
56
|
+
require_relative '../cucumber'
|
57
|
+
|
58
|
+
outputter = Log4r::Outputter[name]
|
59
|
+
|
60
|
+
raise ArgumentError.new "No outputter in loaded configuration file with name #{name}" unless outputter
|
61
|
+
|
62
|
+
return if log.outputters.map(&:name).include? name
|
63
|
+
|
64
|
+
log.add outputter
|
65
|
+
end
|
66
|
+
|
67
|
+
def set_type(step)
|
68
|
+
location = step.location.file.to_s
|
69
|
+
step_name = step.name
|
70
|
+
|
71
|
+
if step_name == "After hook"
|
72
|
+
:after_step
|
73
|
+
elsif step_name == "Before hook" and location.end_with? 'prepare_world.rb'
|
74
|
+
@current_scenario = step.source[1]
|
75
|
+
:before_scenario
|
76
|
+
elsif File.extname(location.to_s) == '.feature'
|
77
|
+
:before_step
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_step_status(type)
|
82
|
+
if type == :after_step
|
83
|
+
@step_running = false
|
84
|
+
elsif type == :before_scenario
|
85
|
+
@step_running = false
|
86
|
+
elsif type == :before_step
|
87
|
+
@step_running = true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'cucumber/formatter/io'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module QAT
|
5
|
+
module Formatter
|
6
|
+
module Scenario
|
7
|
+
class Name
|
8
|
+
include Cucumber::Formatter::Io
|
9
|
+
|
10
|
+
def initialize(runtime, path_or_io, options)
|
11
|
+
@runtime = runtime
|
12
|
+
@io = ensure_io(path_or_io)
|
13
|
+
@to_file = (@io != $stdout)
|
14
|
+
@options = options
|
15
|
+
@scenarios = {}
|
16
|
+
@repeated = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def scenario_name(keyword, name, file_colon_line, source_indent)
|
20
|
+
if @to_file
|
21
|
+
if @scenarios.values.include?(name)
|
22
|
+
@repeated[name] ||= []
|
23
|
+
@repeated[name] << file_colon_line
|
24
|
+
end
|
25
|
+
@scenarios[file_colon_line] = name
|
26
|
+
else
|
27
|
+
puts "#{name}: #{file_colon_line}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def after_features(features)
|
32
|
+
if @to_file
|
33
|
+
content = {
|
34
|
+
scenarios: @scenarios,
|
35
|
+
repeated: @repeated
|
36
|
+
}
|
37
|
+
@io.puts(content.to_json({
|
38
|
+
indent: ' ',
|
39
|
+
space: ' ',
|
40
|
+
object_nl: "\n"
|
41
|
+
}))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'cucumber/formatter/io'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module QAT
|
5
|
+
module Formatter
|
6
|
+
# This formatter prints test scenarios tags information to a JSON format.
|
7
|
+
# Information includes:
|
8
|
+
# - untagged test scenarios
|
9
|
+
# - list of unique tags used
|
10
|
+
# - total number of tags used
|
11
|
+
#
|
12
|
+
# Note: Generated test ids are omitted.
|
13
|
+
#
|
14
|
+
class Tags
|
15
|
+
include Cucumber::Formatter::Io
|
16
|
+
|
17
|
+
#@api private
|
18
|
+
def initialize(runtime, path_or_io, options)
|
19
|
+
@io = ensure_io(path_or_io)
|
20
|
+
@tags = []
|
21
|
+
@scenario_tags = []
|
22
|
+
@total_scenarios = 0
|
23
|
+
@total_scenarios_without_tags = 0
|
24
|
+
@scenarios_without_tags = {}
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
#@api private
|
29
|
+
def after_features(features)
|
30
|
+
publish_result
|
31
|
+
end
|
32
|
+
|
33
|
+
#@api private
|
34
|
+
def before_feature(feature)
|
35
|
+
@feature_tags = []
|
36
|
+
@in_scenarios = false
|
37
|
+
end
|
38
|
+
|
39
|
+
#@api private
|
40
|
+
def tag_name(tag_name)
|
41
|
+
if @in_scenarios
|
42
|
+
@scenario_tags << tag_name unless tag_name.match(/@test#(\d+)/)
|
43
|
+
else
|
44
|
+
@feature_tags << tag_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#@api private
|
49
|
+
def after_tags(tags)
|
50
|
+
@in_scenarios = true unless @in_scenarios
|
51
|
+
end
|
52
|
+
|
53
|
+
#@api private
|
54
|
+
def scenario_name(keyword, name, file_colon_line, source_indent)
|
55
|
+
scenario_tags = @scenario_tags + @feature_tags
|
56
|
+
@tags += scenario_tags
|
57
|
+
@total_scenarios += 1
|
58
|
+
unless scenario_tags.any?
|
59
|
+
@scenarios_without_tags[name] = file_colon_line
|
60
|
+
@total_scenarios_without_tags += 1
|
61
|
+
end
|
62
|
+
@scenario_tags = []
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def publish_result
|
67
|
+
content = {
|
68
|
+
untagged: @scenarios_without_tags,
|
69
|
+
tags:
|
70
|
+
{ unique: @tags.uniq.sort,
|
71
|
+
total: @tags.size }
|
72
|
+
}
|
73
|
+
@io.puts(content.to_json({
|
74
|
+
indent: ' ',
|
75
|
+
space: ' ',
|
76
|
+
object_nl: "\n"
|
77
|
+
}))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|