allure-cucumber 0.6.1 → 2.10.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fe8dfcc9914bde86e27fe7821d7b63d9c20fa287
4
- data.tar.gz: a3c993bd799f18da9987b9b7dcaab15d1975cc90
2
+ SHA256:
3
+ metadata.gz: 9bc852a2f1482e456bd23540b32a67d4146b9d6b8590f27d6da50adbf016a029
4
+ data.tar.gz: 4b4161e222b30491a723de00233e6a7c236085c1c06d8b74244208ff45a6f7b1
5
5
  SHA512:
6
- metadata.gz: 535d1c8ec1f59333ce31cef0d0502975fc79d6986a06e15c5db0da959c9e930d51bd4f8cc6121d7b4df7712b1f77dcb208d30373d238ad560f3769cbc27b90dc
7
- data.tar.gz: ce4ed843506590f910661749399bc45e705cf0cdb5f3e44e97ea9c30601952c1cc44811d9351aa6e6740eef7eca5f4b171f8d5710233341542bd7ff40ff4142d
6
+ metadata.gz: c5ca4b1baa03fd8ddcb77b1f884df7b2231437f15bab7ac4d1905fd74bb43b5d33cc0298b1a788377f1c5bf28774f274cb251b87818bc77cb11af38abc441160
7
+ data.tar.gz: '07806178de6bc0d58b64d41eb3297282589546a508fe92e36d80b3f0b0cbf4cbde35fa1822356db128e0c52154e70b917b5367481a8579ece9c41f5b18b6f2a2'
data/README.md CHANGED
@@ -21,28 +21,20 @@ $ gem install allure-cucumber
21
21
 
22
22
  ## Configuration
23
23
 
24
- By default, Allure XML files are stored in `gen/allure-results`. To change this add the following in `features/support/env.rb` file:
24
+ By default, Allure json files are stored in `reports/allure-results`. To change this add the following in `features/support/env.rb` file:
25
25
 
26
26
  ```ruby
27
- AllureCucumber.configure do |c|
28
- c.output_dir = "/output/dir"
27
+ Allure.configure do |c|
28
+ c.results_directory = "/output/dir"
29
29
  end
30
30
  ```
31
31
 
32
- By default, the Allure XML files from earlier runs are deleted at the start of new run. This can be disabled by:
33
-
34
- ```ruby
35
- AllureCucumber.configure do |c|
36
- c.clean_dir = false
37
- end
38
- ```
39
-
40
- By default, allure-cucumber will analyze your cucumber tags looking for Test Management, Issue Management, and Severity hooks. These hooks will be displayed in the generated allure report (see allure-core for further info).
32
+ By default, allure-cucumber will analyze your cucumber tags looking for Test Management, Issue Management, and Severity hooks. Links to TMS and ISSUE and test severity will be displayed in the report. By default these prefixes are used:
41
33
 
42
34
  ```ruby
43
- DEFAULT_TMS_PREFIX = '@TMS:'
44
- DEFAULT_ISSUE_PREFIX = '@ISSUE:'
45
- DEFAULT_SEVERITY_PREFIX = '@SEVERITY:'
35
+ DEFAULT_TMS_PREFIX = 'TMS:'
36
+ DEFAULT_ISSUE_PREFIX = 'ISSUE:'
37
+ DEFAULT_SEVERITY_PREFIX = 'SEVERITY:'
46
38
  ```
47
39
 
48
40
  Example:
@@ -53,14 +45,15 @@ Example:
53
45
  Then exactly (1) [validation_error] should be visible
54
46
  ```
55
47
 
56
- You can configure what allure-cucumber looks for by making the following changes
48
+ You can configure these prefixes as well as tms and issue tracker urls like this:
57
49
 
58
50
  ```ruby
59
- AllureCucumber.configure do |c|
60
- c.clean_dir = false
61
- c.tms_prefix = '@HIPTEST--'
62
- c.issue_prefix = '@JIRA++'
63
- c.severity_prefix = '@URGENCY:'
51
+ Allure.configure do |c|
52
+ c.link_tms_pattern = "http://www.hiptest.com/tms/{}"
53
+ c.link_issue_pattern = "http://www.jira.com/browse/{}"
54
+ c.tms_prefix = 'HIPTEST--'
55
+ c.issue_prefix = 'JIRA++'
56
+ c.severity_prefix = 'URGENCY:'
64
57
  end
65
58
  ```
66
59
 
@@ -72,6 +65,8 @@ Example:
72
65
  Then exactly (1) [validation_error] should be visible
73
66
  ```
74
67
 
68
+ Additional special tags exists for setting status detail of test scenarios, allure will pick up following tags: `@flaky`, `@known` and `@muted`
69
+
75
70
  ## Usage
76
71
 
77
72
  Put the following in your `features/support/env.rb` file:
@@ -80,17 +75,18 @@ Put the following in your `features/support/env.rb` file:
80
75
  require 'allure-cucumber'
81
76
  ```
82
77
 
83
- Use `--format AllureCucumber::Formatter --out where/you-want-results` while running cucumber or add it to `cucumber.yml`
78
+ Use `--format Allure::CucumberFormatter --out where/you-want-results` while running cucumber or add it to `cucumber.yml`
84
79
 
85
- You can also [attach screenshots](https://github.com/allure-framework/allure-core/wiki/Glossary#attachment), logs or test data to [steps](https://github.com/allure-framework/allure-core/wiki/Glossary#test-step).
80
+ You can also manually attach screenshots and links to test steps and test cases by interacting with allure lifecycle directly. For more info check out `allure-ruby-commons`
86
81
 
87
82
  ```ruby
88
83
  # file: features/support/env.rb
89
84
 
90
- include AllureCucumber::DSL
85
+ require "allure-cucumber"
91
86
 
92
- attach_file(title, file)
87
+ Allure.add_attachment(name: "attachment", source: "Some string", type: Allure::ContentType::TXT, test_case: true)
88
+ Allure.add_link("Custom Url", "http://www.github.com")
93
89
  ```
94
90
 
95
91
  ## How to generate report
96
- This adapter only generates XML files containing information about tests. See [wiki section](https://github.com/allure-framework/allure-core/wiki#generating-report) on how to generate report.
92
+ This adaptor only generates json files containing information about tests. See [wiki section](https://docs.qameta.io/allure/#_reporting) on how to generate report.
@@ -1,52 +1,26 @@
1
- require 'allure-ruby-adaptor-api'
2
- require 'allure-cucumber/version'
3
- require 'allure-cucumber/feature_tracker'
4
- require 'allure-cucumber/dsl'
5
- require 'allure-cucumber/formatter'
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
6
3
 
7
- module AllureCucumber
4
+ require "allure-ruby-commons"
8
5
 
9
- module Config
10
- class << self
11
-
12
- attr_accessor :output_dir, :clean_dir, :tms_prefix, :issue_prefix, :severity_prefix
13
-
14
- DEFAULT_OUTPUT_DIR = 'gen/allure-results'
15
- DEFAULT_TMS_PREFIX = '@TMS:'
16
- DEFAULT_ISSUE_PREFIX = '@ISSUE:'
17
- DEFAULT_SEVERITY_PREFIX = '@SEVERITY:'
18
-
19
- def output_dir
20
- @output_dir || DEFAULT_OUTPUT_DIR
21
- end
22
-
23
- def output_dir=(output_dir)
24
- AllureRubyAdaptorApi::Config.output_dir = output_dir
25
- @output_dir = output_dir
26
- end
27
-
28
- def tms_prefix
29
- @tms_prefix || DEFAULT_TMS_PREFIX
30
- end
31
-
32
- def issue_prefix
33
- @issue_prefix || DEFAULT_ISSUE_PREFIX
34
- end
35
-
36
- def severity_prefix
37
- @severity_prefix || DEFAULT_SEVERITY_PREFIX
38
- end
6
+ require "allure_cucumber/formatter"
7
+ require "allure_cucumber/config"
39
8
 
9
+ module Allure
10
+ class << self
11
+ # Get allure cucumber configuration
12
+ # @return [Allure::CucumberConfig]
13
+ def configuration
14
+ CucumberConfig
40
15
  end
41
- end
42
16
 
43
- class << self
44
- def configure(&block)
45
- yield Config
46
- AllureRubyAdaptorApi.configure do |c|
47
- c.output_dir = Config.output_dir
48
- end
17
+ # Set allure configuration
18
+ # @yieldparam [Allure::CucumberConfig]
19
+ # @yieldreturn [void]
20
+ # @return [void]
21
+ def configure
22
+ yield(CucumberConfig)
49
23
  end
50
24
  end
51
-
52
25
  end
26
+ # rubocop:enable Naming/FileName
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Cucumber::Core::Ast is removed in cucumber-core 4.0 version.
4
+ # This will have to be updated accordingly, once stable version rolls out
5
+
6
+ module Allure
7
+ module AstTransformer
8
+ # Get scenario object
9
+ # @param [Cucumber::Core::Test::Case] test_case
10
+ # @return [Cucumber::Core::Ast::Scenario, Cucumber::Core::Ast::ScenarioOutline]
11
+ def scenario(test_case)
12
+ test_case.source.detect do |it|
13
+ it.is_a?(Cucumber::Core::Ast::Scenario) || it.is_a?(Cucumber::Core::Ast::ScenarioOutline)
14
+ end
15
+ end
16
+
17
+ # Get step object
18
+ # @param [Cucumber::Core::Test::Step] test_case
19
+ # @return [Cucumber::Core::Ast::Step]
20
+ def step(test_step)
21
+ test_step.source.detect { |it| it.is_a?(Cucumber::Core::Ast::Step) }
22
+ end
23
+
24
+ # Get scenario outline example row
25
+ # @param [Cucumber::Core::Test::Case] test_case
26
+ # @return [Cucumber::Core::Ast::ExamplesTable::Row]
27
+ def example_row(test_case)
28
+ test_case.source.detect { |it| it.is_a?(Cucumber::Core::Ast::ExamplesTable::Row) }
29
+ end
30
+
31
+ # Get step multiline argument
32
+ # @param [Cucumber::Core::Test::Step] test_step
33
+ # @return [Cucumber::Core::Ast::DataTable, String]
34
+ def multiline_arg(test_step)
35
+ multiline_arg = step(test_step).multiline_arg
36
+ return if multiline_arg.is_a?(Cucumber::Core::Ast::EmptyMultilineArgument)
37
+
38
+ multiline_arg
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Allure
4
+ class CucumberConfig < Config
5
+ class << self
6
+ DEFAULT_TMS_PREFIX = "TMS:"
7
+ DEFAULT_ISSUE_PREFIX = "ISSUE:"
8
+ DEFAULT_SEVERITY_PREFIX = "SEVERITY:"
9
+
10
+ attr_writer :tms_prefix, :issue_prefix, :severity_prefix
11
+
12
+ # @return [String]
13
+ def tms_prefix
14
+ @tms_prefix || DEFAULT_TMS_PREFIX
15
+ end
16
+
17
+ # @return [String]
18
+ def issue_prefix
19
+ @issue_prefix || DEFAULT_ISSUE_PREFIX
20
+ end
21
+
22
+ # @return [String]
23
+ def severity_prefix
24
+ @severity_prefix || DEFAULT_SEVERITY_PREFIX
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cucumber"
4
+ require "cucumber/core"
5
+ require "digest"
6
+ require "csv"
7
+
8
+ require_relative "ast_transformer"
9
+ require_relative "tag_parser"
10
+
11
+ module Allure
12
+ # Support class for transforming cucumber test entities in to allure model entities
13
+ class AllureCucumberModel
14
+ extend AstTransformer
15
+ extend TagParser
16
+
17
+ class << self
18
+ # Convert to allure test result
19
+ # @param [Cucumber::Core::Test::Case] test_case
20
+ # @return [TestResult]
21
+ def test_result(test_case)
22
+ TestResult.new(
23
+ name: test_case.name,
24
+ description: description(test_case),
25
+ description_html: description(test_case),
26
+ history_id: Digest::MD5.hexdigest(test_case.inspect),
27
+ full_name: "#{test_case.feature.name}: #{test_case.name}",
28
+ labels: labels(test_case),
29
+ links: links(test_case),
30
+ parameters: parameters(test_case) || [],
31
+ status_details: Allure::StatusDetails.new(**status_detail_tags(test_case.tags.map(&:name))),
32
+ )
33
+ end
34
+
35
+ # Convert to allure step result
36
+ # @param [Cucumber::Core::Test::Step] test_step
37
+ # @return [StepResult]
38
+ def step_result(test_step)
39
+ StepResult.new(
40
+ name: "#{step(test_step).keyword}#{test_step.text}",
41
+ attachments: [multiline_arg_attachment(test_step)].compact,
42
+ )
43
+ end
44
+
45
+ # Convert to allure step result
46
+ # @param [Cucumber::Core::Test::Step] test_step
47
+ # @return [StepResult]
48
+ def fixture_result(test_step)
49
+ location = test_step.location.to_s.split("/").last
50
+ FixtureResult.new(name: location)
51
+ end
52
+
53
+ # Get failure details
54
+ # @param [Cucumber::Core::Test::Result] result <description>
55
+ # @return [Hash<Symbol, String>]
56
+ def failure_details(result)
57
+ return { message: result.exception.message, trace: result.exception.backtrace.join("\n") } if result.failed?
58
+ return { message: result.message, trace: result.backtrace.join("\n") } if result.undefined?
59
+
60
+ {}
61
+ end
62
+
63
+ private
64
+
65
+ # Get thread specific lifecycle
66
+ # @return [Allure::AllureLifecycle]
67
+ def lifecycle
68
+ Allure.lifecycle
69
+ end
70
+
71
+ # @param [Cucumber::Core::Test::Case] test_case
72
+ # @return [Array<Allure::Label>]
73
+ def labels(test_case)
74
+ labels = []
75
+ labels << ResultUtils.framework_label("cucumber")
76
+ labels << ResultUtils.feature_label(test_case.feature.name)
77
+ labels << ResultUtils.package_label(test_case.feature.name)
78
+ labels << ResultUtils.suite_label(test_case.feature.name)
79
+ labels << ResultUtils.story_label(test_case.name)
80
+ labels << ResultUtils.test_class_label(test_case.name)
81
+ unless test_case.tags.empty?
82
+ labels.push(*tag_labels(test_case.tags))
83
+ labels << severity(test_case.tags)
84
+ end
85
+
86
+ labels
87
+ end
88
+
89
+ # @param [Cucumber::Core::Test::Case] test_case
90
+ # @return [Array<Allure::Link>]
91
+ def links(test_case)
92
+ return [] unless test_case.tags
93
+
94
+ tms_links(test_case.tags) + issue_links(test_case.tags)
95
+ end
96
+
97
+ # @param [Cucumber::Core::Test::Case] test_case
98
+ # @return [Array<Allure::Parameter>]
99
+ def parameters(test_case)
100
+ example_row(test_case)&.values&.map { |value| Parameter.new("argument", value) }
101
+ end
102
+
103
+ # @param [Cucumber::Core::Test::Case] test_case
104
+ # @return [String]
105
+ def description(test_case)
106
+ scenario = scenario(test_case)
107
+ scenario.description.empty? ? "Location - #{scenario.file_colon_line}" : scenario.description.strip
108
+ end
109
+
110
+ # @param [Cucumber::Core::Test::Step] test_step
111
+ # @return [Allure::Attachment]
112
+ def multiline_arg_attachment(test_step)
113
+ arg = multiline_arg(test_step)
114
+ return unless arg
115
+
116
+ arg.data_table? ? data_table_attachment(arg) : docstring_attachment(arg)
117
+ end
118
+
119
+ # @param [Cucumber::Core::Ast::DataTable] multiline_arg
120
+ # @return [Allure::Attachment]
121
+ def data_table_attachment(multiline_arg)
122
+ attachment = lifecycle.prepare_attachment("data-table", ContentType::CSV)
123
+ csv = multiline_arg.raw.each_with_object([]) { |row, arr| arr.push(row.to_csv) }.join("")
124
+ lifecycle.write_attachment(csv, attachment)
125
+ attachment
126
+ end
127
+
128
+ # @param [String] multiline_arg
129
+ # @return [String]
130
+ def docstring_attachment(multiline_arg)
131
+ attachment = lifecycle.prepare_attachment("docstring", ContentType::TXT)
132
+ lifecycle.write_attachment(multiline_arg.content, attachment)
133
+ attachment
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "cucumber_model"
4
+
5
+ module Allure
6
+ # Main formatter class. Translates cucumber event to allure lifecycle
7
+ class CucumberFormatter
8
+ HOOK_HANDLERS = {
9
+ "Before hook" => :start_prepare_fixture,
10
+ "After hook" => :start_tear_down_fixture,
11
+ }.freeze
12
+ ALLURE_STATUS = {
13
+ failed: Status::FAILED,
14
+ skipped: Status::SKIPPED,
15
+ passed: Status::PASSED,
16
+ }.freeze
17
+
18
+ # @param [Cucumber::Configuration] config
19
+ def initialize(config)
20
+ Allure::Config.results_directory = config.out_stream if config.out_stream.is_a?(String)
21
+ config.on_event(:test_case_started, &method(:on_test_case_started))
22
+ config.on_event(:test_step_started, &method(:on_test_step_started))
23
+ config.on_event(:test_step_finished, &method(:on_test_step_finished))
24
+ config.on_event(:test_case_finished, &method(:on_test_case_finished))
25
+ end
26
+
27
+ # Handle test case started event
28
+ # @param [Cucumber::Core::Events::TestCaseStarted] event
29
+ # @return [void]
30
+ def on_test_case_started(event)
31
+ lifecycle.start_test_container(TestResultContainer.new(name: event.test_case.name))
32
+ lifecycle.start_test_case(AllureCucumberModel.test_result(event.test_case))
33
+ end
34
+
35
+ # Handle test step started event
36
+ # @param [Cucumber::Core::Events::TestStepStarted] event
37
+ # @return [void]
38
+ def on_test_step_started(event)
39
+ hook?(event.test_step) ? handle_hook_started(event.test_step) : handle_step_started(event.test_step)
40
+ end
41
+
42
+ # Handle test step finished event
43
+ # @param [Cucumber::Core::Events::TestStepFinished] event
44
+ # @return [void]
45
+ def on_test_step_finished(event)
46
+ return if prepare_world_hook?(event.test_step)
47
+
48
+ update_block = proc do |step|
49
+ step.stage = Stage::FINISHED
50
+ step.status = ALLURE_STATUS.fetch(event.result.to_sym, Status::BROKEN)
51
+ end
52
+ step_type = hook?(event.test_step) ? "fixture" : "test_step"
53
+
54
+ lifecycle.public_send("update_#{step_type}", &update_block)
55
+ lifecycle.public_send("stop_#{step_type}")
56
+ end
57
+
58
+ # Handle test case finished event
59
+ # @param [Cucumber::Core::Events::TestCaseFinished] event
60
+ # @return [void]
61
+ def on_test_case_finished(event)
62
+ failure_details = AllureCucumberModel.failure_details(event.result)
63
+ status = ALLURE_STATUS.fetch(event.result.to_sym, Status::BROKEN)
64
+ lifecycle.update_test_case do |test_case|
65
+ test_case.stage = Stage::FINISHED
66
+ test_case.status = event.result.failed? ? Allure::ResultUtils.status(event.result&.exception) : status
67
+ test_case.status_details.flaky = event.result.flaky?
68
+ test_case.status_details.message = failure_details[:message]
69
+ test_case.status_details.trace = failure_details[:trace]
70
+ end
71
+ lifecycle.stop_test_case
72
+ lifecycle.stop_test_container
73
+ end
74
+
75
+ private
76
+
77
+ # Get thread specific lifecycle
78
+ # @return [Allure::AllureLifecycle]
79
+ def lifecycle
80
+ Allure.lifecycle
81
+ end
82
+
83
+ # @param [Cucumber::Core::Test::Step] test_step <description>
84
+ # @return [Boolean]
85
+ def hook?(test_step)
86
+ HOOK_HANDLERS.key?(test_step.text)
87
+ end
88
+
89
+ # @param [Cucumber::Core::Test::Step] test_step
90
+ # @return [Boolean]
91
+ def prepare_world_hook?(test_step)
92
+ hook?(test_step) && test_step.inspect.include?("prepare_world.rb")
93
+ end
94
+
95
+ # @param [Cucumber::Core::Test::Step] test_step
96
+ # @return [void]
97
+ def handle_step_started(test_step)
98
+ lifecycle.start_test_step(AllureCucumberModel.step_result(test_step))
99
+ end
100
+
101
+ # @param [Cucumber::Core::Test::Step] test_step
102
+ # @return [void]
103
+ def handle_hook_started(test_step)
104
+ return if prepare_world_hook?(test_step)
105
+
106
+ lifecycle.public_send(HOOK_HANDLERS[test_step.text], AllureCucumberModel.fixture_result(test_step))
107
+ end
108
+ end
109
+ end