├── CHANGELOG.md
├── LICENSE
├── LICENSE.aventstack
├── README.md
├── exceldb.png
├── extentreports-cucumber6-adapter
├── .gitignore
├── pom-nexus.xml
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── aventstack
│ │ └── extentreports
│ │ ├── cucumber
│ │ └── adapter
│ │ │ ├── ExtentCucumberAdapter.java
│ │ │ ├── TestSourcesModel.java
│ │ │ └── URLOutputStream.java
│ │ └── service
│ │ └── ExtentService.java
│ └── test
│ ├── java
│ └── cucumber
│ │ └── examples
│ │ └── java
│ │ └── calculator
│ │ ├── Configurer.java
│ │ ├── DateCalculator.java
│ │ ├── DateStepdefs.java
│ │ ├── Example.java
│ │ ├── RpnCalculator.java
│ │ ├── RpnCalculatorStepdefs.java
│ │ ├── RunCukesTest.java
│ │ ├── ScreenShotStepDefinition.java
│ │ └── ShoppingStepdefs.java
│ └── resources
│ ├── com
│ └── aventstack
│ │ └── adapter
│ │ ├── extent.properties
│ │ ├── html-config.xml
│ │ ├── klov.properties
│ │ └── spark-config.xml
│ ├── cucumber
│ └── examples
│ │ └── java
│ │ └── calculator
│ │ ├── basic_arithmetic.feature
│ │ ├── date_calculator.feature
│ │ ├── screen.feature
│ │ ├── shopping.feature
│ │ └── skipdef.feature
│ └── logo.png
└── summary.png
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | # 2.18.0 (2023-8-10)
5 |
6 | * Updated extent report version
7 | * Updated java version to 11
8 | * Updated dependencies version
9 |
10 | # 2.17.0 (2023-05-12)
11 |
12 | * Update pdf report version
13 |
14 | # 2.16.0 (2023-02-01)
15 |
16 | * Added excel reporter
17 |
18 | # 2.15.0 (2022-11-14)
19 |
20 | * Add support for status filter for html report
21 | * Updated pdf report data collector version to 2.9.1
22 |
23 | # 2.14.3 (2022-11-11)
24 |
25 | * Add support for status filter for PDF report [Issue 55](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/55)
26 |
27 | # 2.14.2 (2022-11-10)
28 |
29 | * Add support for status filter for Spark report [Issue 54](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/54)
30 |
31 | # 2.14.1 (2022-11-07)
32 |
33 | * Updated pdf report data collector version to 2.8.0
34 |
35 | # 2.14.0 (2022-11-05)
36 |
37 | * Add device and author information as tags [Issue 52](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/52)
38 | * Base folder report name custom delimiter setting [Issue 53](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/53)
39 |
40 | # 2.13.1 (2022-11-02)
41 |
42 | * Fixed tag count & test display for scenario outline [Issue 51](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/51)
43 |
44 | # 2.13.0 (2022-6-19)
45 |
46 | * Updated pdf report data collector version to 2.7.0
47 |
48 | # 2.12.0 (2022-6-11)
49 |
50 | * Updated pdf report data collector version to 2.6.0
51 |
52 | # 2.11.1 (2022-05-11)
53 |
54 | * Updated pdf report data collector version to 2.5.1
55 |
56 | # 2.11.0 (2022-05-09)
57 |
58 | * Updated pdf report data collector version to 2.5.0
59 |
60 | # 2.10.4 (2022-04-28)
61 |
62 | * Updated pdf report data collector version to 2.4.1
63 |
64 | # 2.10.3 (2022-04-23)
65 |
66 | * Updated pdf report data collector version to 2.4.0
67 |
68 | # 2.10.2 (2022-04-12)
69 |
70 | * Updated pdf report data collector version to 2.3.0
71 |
72 | # 2.10.1 (2022-04-09)
73 | * Updated HTML extent report version
74 |
75 | # 2.10.0 (2022-03-06)
76 |
77 | * Updated pdf report data collector version to 2.1.0
78 |
79 | # 2.9.0 (2022-01-16)
80 |
81 | * Add HTMLExtentReporter to adapter [Issue 48](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/48)
82 | * Scenario Outline with non default dialect display issue [Issue 47](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/47)
83 |
84 | # 2.8.4 (2021-09-14)
85 |
86 | * Updated pdf report data collector version to 1.7.4
87 |
88 | # 2.8.3 (2021-08-3)
89 |
90 | * Remove temporary base64 images for pdf [Issue 40](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/40)]
91 | * Updated pdf reporter version to 2.2.4
92 |
93 | # 2.8.2 (2021-06-21)
94 |
95 | * Updated pdf reporter version to 2.2.3
96 |
97 | # 2.8.1 (2021-04-20)
98 |
99 | * Updated pdf reporter version to 2.2.1
100 |
101 | # 2.8.0 (2021-04-16)
102 |
103 | * Store step pending status exception stacktrace [Issue 37](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/37)
104 | * Updated extentreport version to 5.0.6
105 | * Updated pdf reporter version to 2.2.0
106 |
107 | # 2.7.0 (2021-03-09)
108 |
109 | * Incorrect scenario count for tags\categories [Issue 33](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/33)
110 |
111 | # 2.6.0 (2020-12-13)
112 |
113 | * Support to attach base64 images [Issue 11](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/11)
114 |
115 | # 2.5.0 (2020-11-19)
116 |
117 | * Support dialect in adapter [Issue 29](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/29)
118 | * Upgrade extentreport version
119 | * Upgrade pdf reporter version
120 |
121 | # 2.4.0 (2020-11-05)
122 |
123 | * Klov reporter initialization fails with NPE [Issue 26](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/26)
124 | * Parallel execution does not work for junit runner [Issue 27](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/27)
125 | * Fail pending step in strict mode [Issue 25](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/25)
126 | * Upgrade pdf reporter version
127 |
128 | ## 2.3.0 (2020-10-24)
129 |
130 | * "Passed" Step duration not correct when multiple logs are attached [Issue 24](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/24)
131 |
132 | ## 2.2.0 (2020-10-21)
133 |
134 | * Option to default your report to Dashboard [Issue 16](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/16)
135 | * Add support for pdf reporter [Issue 20](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/20)
136 | * Ability to determine hook type [Issue 21](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/21)
137 |
138 | ## 2.1.0 (2020-10-14)
139 |
140 | * Fixed missing parameterized values in scenario outline names [Issue 15](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/15)
141 |
142 | ## 2.0.0 (2020-09-06)
143 |
144 | * Upgrade adapter to support extent version 5 [Issue 5](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/5)
145 | * Remove StrictAware interface as deprecated [Issue 4](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/4)
146 |
147 | ## 1.2.0 (2020-08-11)
148 |
149 | * Add date and time to report folders [Issue 8](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/8)
150 | * Fix report folder name issue [Issue 9](https://github.com/grasshopper7/extentreports-cucumber5-adapter/issues/9)
151 |
152 | ## 1.1.0 (2020-07-21)
153 |
154 | * Support for Json formatter [Issue 3](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/3)
155 | * Fixed docstring display [Issue 2](https://github.com/grasshopper7/extentreports-cucumber6-adapter/issues/2)
156 |
157 | ## 1.0.0 (2020-06-13)
158 |
159 | * Released based on extentreports-cucumber5-adapter
160 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 grasshopper
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.aventstack:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 aventstack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This deals with generating **Extent reports for Cucumber-JVM version 6** using the ExtentReports Cucumber **Adapter Plugin**. For more details refer to this [article](http://ghchirp.site/2098/). A sample usage of this adapter can be found [here](https://github.com/grasshopper7/cuke6-extent-adapter-report).
2 |
3 | To **build** from source use ```install -Dmaven.test.failure.ignore=true``` or ```install -Dmaven.test.skip=true```. This ignores intentional test failures from stopping the build.
4 |
5 | **Dependency** - To work with the latest [ExtentReports version 5](https://github.com/extent-framework/extentreports-java/wiki), which includes support for latest **Spark, PDF *(New Feature, check 'Extent PDF Reporter' section below)*, Ported HTML *(New Feature, check 'HTML Reporter' section)*, Klov and Json** reporters, add the below dependency. The HTML and Logger reporters, among others, have been deprecated. For more details refer to the **POM Dependencies** section of the [article](http://ghchirp.site/2098/).
6 |
7 | ```
8 |
9 | tech.grasshopper
10 | extentreports-cucumber6-adapter
11 | 2.18.0
12 |
13 | ```
14 |
15 | To work with the older ExtentReports version 4, add the below dependency.
16 |
17 | ```
18 |
19 | tech.grasshopper
20 | extentreports-cucumber6-adapter
21 | 1.2.0
22 |
23 | ```
24 |
25 | **Report Attachments** - To add attachments, like screen images, two settings need to be added to the extent.properties. First property, named **screenshot.dir**, is the directory where the attachments are stored. Second is **screenshot.rel.path**, which is the relative path from the report file to the screenshot directory. For more details refer to the **Report Attachments** section of the [article](http://ghchirp.site/2098/).
26 |
27 | ```
28 | extent.reporter.spark.out=test-output/SparkReport/Spark.html
29 |
30 | screenshot.dir=test-output/
31 | screenshot.rel.path=../
32 | ```
33 |
34 |
35 | **Extent Excel Reporter** *(NEW FEATURE)* - The Excel reporter summarizes the test run results in a **dashboard** and other worksheets with **feature, scenario, exception, tags, authors, devices details**. A complete sample report can be found [here](https://github.com/grasshopper7/cuke6-extent-adapter-report/tree/master/cuke6-extent-adapter-report/excelreport).
36 |
37 |
38 | 
39 |
40 |
41 | The Excel report needs to be enabled in the extent.properties file.
42 | ```
43 | extent.reporter.excel.start=true
44 | extent.reporter.excel.out=test output/ExcelReport/ExtentExcel.xlsx
45 | ```
46 |
47 |
48 | **Extent PDF Reporter** *(NEW FEATURE)* - The PDF reporter summarizes the test run results in a **dashboard** and other sections with **feature, scenario and step details**.
49 |
50 |
51 | 
52 |
53 |
54 | The PDF report is needs to be enabled in the extent.properties file.
55 | ```
56 | extent.reporter.pdf.start=true
57 | extent.reporter.pdf.out=test output/PdfReport/ExtentPdf.pdf
58 | ```
59 | The default color settings can be modified by using a YAML config file, named pdf-config.yaml in the project src/test/resource folder. The detailed documentation for this feature is available in this [article](http://ghchirp.site/2224/).
60 |
61 |
62 | **Ported HTML Reporter** *(NEW FEATURE)* - The original HTML Extent Reporter was deprecated in 4.1.3 and removed in 5.0.0. The HTML report available in the adapter is based on the same code base and is similar in appearance. The major changes are in the Freemarker template code which have been modified to work with the Extent Reports version 5.
63 |
64 | The HTML report needs to be enabled in the extent.properties file.
65 | ```
66 | extent.reporter.html.start=true
67 | extent.reporter.html.out=test-output/HtmlReport/ExtentHtml.html
68 | ```
69 |
70 | **Customized Report Folder Name** *(NEW FEATURE)* - To enable report folder name with date and\or time details, two settings need to be added to the extent.properties. These are **basefolder.name** and **basefolder.datetimepattern**. These will be merged to create the base folder name, inside which the reports will be generated. The basefolder.datetimepattern value should be a **valid date time formatter pattern**. For more details refer to the **Customized Report Folder Name** section of the [article](http://ghchirp.site/2098/).
71 |
72 | ```
73 | extent.reporter.spark.out=test-output/SparkReport/
74 |
75 | screenshot.dir=test-output/
76 | screenshot.rel.path=../
77 |
78 | basefolder.name=reports
79 | basefolder.datetimepattern=d-MMM-YY HH-mm-ss
80 | ```
81 |
82 | With the above settings, a base folder with the name '**reports 10-Aug-20 10-25-50**' will contain the reports. Screenshots if any, will be located inside the '**reports 10-Aug-20 10-25-50/test-output**' folder structure. Similarly the report will be created in the '**reports 10-Aug-20 10-25-50/test-output/SparkReport**' folder structure.
83 |
84 | **Attach Image as Base64 String** *(NEW FEATURE)* - This feature can be used to attach images to the Spark report by setting the **src attribute of the img tag to a Base64 encoded string** of the image. When this feature is used, no physical file is created. There is no need to modify any step definition code to use this. To enable this, use the below settings in extent.properties, which is false by default.
85 |
86 | ```
87 | extent.reporter.spark.base64imagesrc=true
88 | ```
89 | The Spark report file size will be **pretty large and there could be memory issues** if a substantial number of images are present. A generic thumbnail is created and on clicking the image is displayed.
90 |
91 | **Environment or System Info Properties** *(NEW FEATURE)* - It is now possible to add environment or system info properties in the extent.properties or pass them in the maven command line. The key string should begin with the prefix - 'systeminfo.'. **Be careful of the dot at the end**. For more details refer to the **Environment or System Info Properties** section of the [article](http://ghchirp.site/2098/).
92 |
93 | ```
94 | systeminfo.os=windows
95 | ```
96 |
--------------------------------------------------------------------------------
/exceldb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grasshopper7/extentreports-cucumber6-adapter/83dad648d859c244e33fce99238c378df05987fa/exceldb.png
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
3 | /test-output/
4 |
5 |
6 | /.settings/
7 |
8 |
9 |
10 | /.classpath
11 |
12 |
13 |
14 | /.project
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/pom-nexus.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | tech.grasshopper
7 | extentreports-cucumber6-adapter
8 | 2.18.0
9 | extentreports-cucumber6-adapter
10 | https://ghchirp.site/2098/
11 | Cucumber-JVM 6 adapter for Extent Framework
12 |
13 |
14 |
15 | MIT License
16 | http://www.opensource.org/licenses/mit-license.php
17 |
18 |
19 |
20 |
21 |
22 | Grass Hopper
23 | grass.hopper.moc@gmail.com
24 | Grasshopper
25 | http://ghchirp.site/
26 |
27 |
28 |
29 |
30 | UTF-8
31 | UTF-8
32 | 6.10.4
33 | 5.0.9
34 | 2.12.0
35 | 1.1.0
36 | 1.4.0
37 |
38 |
39 |
40 | scm:git:git://github.com/grasshopper7/extentreports-cucumber6-adapter.git
41 | scm:git:ssh://github.com:grasshopper7/extentreports-cucumber6-adapter.git
42 | https://github.com/grasshopper7/extentreports-cucumber6-adapter
43 |
44 |
45 |
46 |
47 | com.aventstack
48 | extentreports
49 | ${extent.version}
50 |
51 |
52 | tech.grasshopper
53 | extent-pdf-report
54 | ${pdfreporter.version}
55 |
56 |
57 | com.aventstack
58 | klov-reporter
59 | ${extent.version}
60 |
61 |
62 | tech.grasshopper
63 | htmlextentreporter
64 | ${htmlreporter.version}
65 |
66 |
67 | tech.grasshopper
68 | extent-excel-report
69 | ${excelreporter.version}
70 |
71 |
72 | io.cucumber
73 | cucumber-java
74 | ${cucumber.version}
75 | provided
76 |
77 |
78 | io.cucumber
79 | cucumber-testng
80 | ${cucumber.version}
81 | test
82 |
83 |
84 | org.mongodb
85 | mongodb-driver
86 | 3.3.0
87 |
88 |
89 | com.fasterxml.jackson.core
90 | jackson-databind
91 | 2.14.0
92 | test
93 |
94 |
95 | com.fasterxml.jackson.datatype
96 | jackson-datatype-jsr310
97 | 2.14.0
98 | test
99 |
100 |
101 | io.github.bonigarcia
102 | webdrivermanager
103 | 3.8.1
104 | test
105 |
106 |
107 | org.seleniumhq.selenium
108 | selenium-java
109 | 3.141.59
110 | test
111 |
112 |
113 |
114 |
115 |
116 | ossrh
117 | https://oss.sonatype.org/content/repositories/snapshots
118 |
119 |
120 | ossrh
121 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
122 |
123 |
124 |
125 |
126 |
127 |
128 | org.apache.maven.plugins
129 | maven-compiler-plugin
130 | 3.8.1
131 |
132 | 11
133 | 11
134 |
135 |
136 |
137 | org.apache.maven.plugins
138 | maven-resources-plugin
139 | 3.2.0
140 |
141 |
142 | org.sonatype.plugins
143 | nexus-staging-maven-plugin
144 | 1.6.8
145 | true
146 |
147 | ossrh
148 | https://oss.sonatype.org/
149 | true
150 |
151 |
152 |
153 | org.apache.maven.plugins
154 | maven-source-plugin
155 | 3.2.0
156 |
157 |
158 | attach-sources
159 |
160 | jar-no-fork
161 |
162 |
163 |
164 |
165 |
166 | org.apache.maven.plugins
167 | maven-javadoc-plugin
168 | 3.2.0
169 |
170 |
171 | attach-javadocs
172 |
173 | jar
174 |
175 |
176 |
177 |
178 |
179 | org.apache.maven.plugins
180 | maven-gpg-plugin
181 | 1.6
182 |
183 |
184 | sign-artifacts
185 | verify
186 |
187 | sign
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | tech.grasshopper
7 | extentreports-cucumber6-adapter
8 | 2.18.0
9 | extentreports-cucumber6-adapter
10 | https://ghchirp.site/2098/
11 | Cucumber-JVM 6 adapter for Extent Framework
12 |
13 |
14 |
15 | MIT License
16 | http://www.opensource.org/licenses/mit-license.php
17 |
18 |
19 |
20 |
21 |
22 | Grass Hopper
23 | grass.hopper.moc@gmail.com
24 | Grasshopper
25 | http://ghchirp.site/
26 |
27 |
28 |
29 |
30 | UTF-8
31 | UTF-8
32 | 6.10.4
33 | 5.1.0
34 | 2.12.0
35 | 1.1.0
36 | 1.4.0
37 |
38 |
39 |
40 |
41 | com.aventstack
42 | extentreports
43 | ${extent.version}
44 |
45 |
46 | tech.grasshopper
47 | extent-pdf-report
48 | ${pdfreporter.version}
49 |
50 |
51 | com.aventstack
52 | klov-reporter
53 | ${extent.version}
54 |
55 |
56 | tech.grasshopper
57 | htmlextentreporter
58 | ${htmlreporter.version}
59 |
60 |
61 | tech.grasshopper
62 | extent-excel-report
63 | ${excelreporter.version}
64 |
65 |
66 | io.cucumber
67 | cucumber-java
68 | ${cucumber.version}
69 | provided
70 |
71 |
72 | io.cucumber
73 | cucumber-testng
74 | ${cucumber.version}
75 | test
76 |
77 |
78 | org.mongodb
79 | mongodb-driver
80 | 3.3.0
81 |
82 |
83 | com.fasterxml.jackson.core
84 | jackson-databind
85 | 2.14.0
86 | test
87 |
88 |
89 | com.fasterxml.jackson.datatype
90 | jackson-datatype-jsr310
91 | 2.14.0
92 | test
93 |
94 |
95 | io.github.bonigarcia
96 | webdrivermanager
97 | 3.8.1
98 | test
99 |
100 |
101 | org.seleniumhq.selenium
102 | selenium-java
103 | 3.141.59
104 | test
105 |
106 |
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-compiler-plugin
113 | 3.8.1
114 |
115 | 11
116 | 11
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-resources-plugin
122 | 3.2.0
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/main/java/com/aventstack/extentreports/cucumber/adapter/ExtentCucumberAdapter.java:
--------------------------------------------------------------------------------
1 | package com.aventstack.extentreports.cucumber.adapter;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 | import java.io.UnsupportedEncodingException;
7 | import java.net.URI;
8 | import java.net.URISyntaxException;
9 | import java.net.URL;
10 | import java.nio.file.Paths;
11 | import java.util.ArrayList;
12 | import java.util.Base64;
13 | import java.util.Collection;
14 | import java.util.HashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 | import java.util.Set;
18 | import java.util.concurrent.ConcurrentHashMap;
19 | import java.util.concurrent.atomic.AtomicInteger;
20 | import java.util.stream.Collectors;
21 |
22 | import com.aventstack.extentreports.ExtentTest;
23 | import com.aventstack.extentreports.GherkinKeyword;
24 | import com.aventstack.extentreports.MediaEntityBuilder;
25 | import com.aventstack.extentreports.Status;
26 | import com.aventstack.extentreports.gherkin.model.Asterisk;
27 | import com.aventstack.extentreports.gherkin.model.ScenarioOutline;
28 | import com.aventstack.extentreports.markuputils.MarkupHelper;
29 | import com.aventstack.extentreports.model.Test;
30 | import com.aventstack.extentreports.service.ExtentService;
31 |
32 | import io.cucumber.core.exception.CucumberException;
33 | import io.cucumber.messages.Messages.GherkinDocument.Feature;
34 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario;
35 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario.Examples;
36 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Step;
37 | import io.cucumber.messages.Messages.GherkinDocument.Feature.TableRow;
38 | import io.cucumber.messages.Messages.GherkinDocument.Feature.TableRow.TableCell;
39 | import io.cucumber.plugin.ConcurrentEventListener;
40 | import io.cucumber.plugin.event.DataTableArgument;
41 | import io.cucumber.plugin.event.DocStringArgument;
42 | import io.cucumber.plugin.event.EmbedEvent;
43 | import io.cucumber.plugin.event.EventHandler;
44 | import io.cucumber.plugin.event.EventPublisher;
45 | import io.cucumber.plugin.event.HookTestStep;
46 | import io.cucumber.plugin.event.PickleStepTestStep;
47 | import io.cucumber.plugin.event.Result;
48 | import io.cucumber.plugin.event.StepArgument;
49 | import io.cucumber.plugin.event.TestCase;
50 | import io.cucumber.plugin.event.TestCaseStarted;
51 | import io.cucumber.plugin.event.TestRunFinished;
52 | import io.cucumber.plugin.event.TestSourceRead;
53 | import io.cucumber.plugin.event.TestStepFinished;
54 | import io.cucumber.plugin.event.TestStepStarted;
55 | import io.cucumber.plugin.event.WriteEvent;
56 |
57 | /**
58 | * A port of Cucumber-JVM (MIT licensed) HtmlFormatter for Extent Framework
59 | * Original source:
60 | * https://github.com/cucumber/cucumber-jvm/blob/master/core/src/main/java/cucumber/runtime/formatter/HTMLFormatter.java
61 | *
62 | */
63 | public class ExtentCucumberAdapter implements ConcurrentEventListener {
64 |
65 | private static Map featureMap = new ConcurrentHashMap<>();
66 | private static ThreadLocal featureTestThreadLocal = new InheritableThreadLocal<>();
67 | private static Map scenarioOutlineMap = new ConcurrentHashMap<>();
68 | private static ThreadLocal scenarioOutlineThreadLocal = new InheritableThreadLocal<>();
69 | private static ThreadLocal scenarioThreadLocal = new InheritableThreadLocal<>();
70 | private static ThreadLocal isHookThreadLocal = new InheritableThreadLocal<>();
71 | private static ThreadLocal stepTestThreadLocal = new InheritableThreadLocal<>();
72 | private static ThreadLocal> featureTagsThreadLocal = new InheritableThreadLocal<>();
73 | private static ThreadLocal> scenarioOutlineTagsThreadLocal = new InheritableThreadLocal<>();
74 |
75 | @SuppressWarnings("serial")
76 | private static final Map MIME_TYPES_EXTENSIONS = new HashMap() {
77 | {
78 | put("image/bmp", "bmp");
79 | put("image/gif", "gif");
80 | put("image/jpeg", "jpeg");
81 | put("image/jpg", "jpg");
82 | put("image/png", "png");
83 | put("image/svg+xml", "svg");
84 | // TODO Video, txt, html, pdf etc.
85 | // put("video/ogg", "ogg");
86 | // put("video/mp4", "mp4");
87 | }
88 | };
89 |
90 | private static final AtomicInteger EMBEDDED_INT = new AtomicInteger(0);
91 |
92 | private final TestSourcesModel testSources = new TestSourcesModel();
93 |
94 | private ThreadLocal currentFeatureFile = new ThreadLocal<>();
95 | private ThreadLocal currentScenarioOutline = new InheritableThreadLocal<>();
96 | private ThreadLocal currentExamples = new InheritableThreadLocal<>();
97 |
98 | private EventHandler testSourceReadHandler = new EventHandler() {
99 | @Override
100 | public void receive(TestSourceRead event) {
101 | handleTestSourceRead(event);
102 | }
103 | };
104 | private EventHandler caseStartedHandler = new EventHandler() {
105 | @Override
106 | public void receive(TestCaseStarted event) {
107 | handleTestCaseStarted(event);
108 | }
109 | };
110 | private EventHandler stepStartedHandler = new EventHandler() {
111 | @Override
112 | public void receive(TestStepStarted event) {
113 | handleTestStepStarted(event);
114 | }
115 | };
116 | private EventHandler stepFinishedHandler = new EventHandler() {
117 | @Override
118 | public void receive(TestStepFinished event) {
119 | handleTestStepFinished(event);
120 | }
121 | };
122 | private EventHandler embedEventhandler = new EventHandler() {
123 | @Override
124 | public void receive(EmbedEvent event) {
125 | handleEmbed(event);
126 | }
127 | };
128 | private EventHandler writeEventhandler = new EventHandler() {
129 | @Override
130 | public void receive(WriteEvent event) {
131 | handleWrite(event);
132 | }
133 | };
134 | private EventHandler runFinishedHandler = new EventHandler() {
135 | @Override
136 | public void receive(TestRunFinished event) {
137 | finishReport();
138 | }
139 | };
140 |
141 | public ExtentCucumberAdapter(String arg) {
142 | ExtentService.getInstance();
143 | }
144 |
145 | @Override
146 | public void setEventPublisher(EventPublisher publisher) {
147 | publisher.registerHandlerFor(TestSourceRead.class, testSourceReadHandler);
148 | publisher.registerHandlerFor(TestCaseStarted.class, caseStartedHandler);
149 | publisher.registerHandlerFor(TestStepStarted.class, stepStartedHandler);
150 | publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
151 | publisher.registerHandlerFor(EmbedEvent.class, embedEventhandler);
152 | publisher.registerHandlerFor(WriteEvent.class, writeEventhandler);
153 | publisher.registerHandlerFor(TestRunFinished.class, runFinishedHandler);
154 | }
155 |
156 | private void handleTestSourceRead(TestSourceRead event) {
157 | testSources.addTestSourceReadEvent(event.getUri(), event);
158 | }
159 |
160 | private synchronized void handleTestCaseStarted(TestCaseStarted event) {
161 | handleStartOfFeature(event.getTestCase());
162 | handleScenarioOutline(event.getTestCase());
163 | createTestCase(event.getTestCase());
164 | }
165 |
166 | private synchronized void handleTestStepStarted(TestStepStarted event) {
167 | isHookThreadLocal.set(false);
168 |
169 | if (event.getTestStep() instanceof HookTestStep) {
170 | ExtentTest t = scenarioThreadLocal.get().createNode(Asterisk.class, event.getTestStep().getCodeLocation(),
171 | (((HookTestStep) event.getTestStep()).getHookType()).toString().toUpperCase());
172 | stepTestThreadLocal.set(t);
173 | isHookThreadLocal.set(true);
174 | }
175 |
176 | if (event.getTestStep() instanceof PickleStepTestStep) {
177 | PickleStepTestStep testStep = (PickleStepTestStep) event.getTestStep();
178 | createTestStep(testStep);
179 | }
180 | }
181 |
182 | private synchronized void handleTestStepFinished(TestStepFinished event) {
183 | updateResult(event.getResult());
184 | }
185 |
186 | private synchronized void updateResult(Result result) {
187 | Test test = stepTestThreadLocal.get().getModel();
188 | switch (result.getStatus().name().toLowerCase()) {
189 | case "failed":
190 | stepTestThreadLocal.get().fail(result.getError());
191 | break;
192 | case "undefined":
193 | stepTestThreadLocal.get().fail("Step undefined");
194 | break;
195 | case "pending":
196 | stepTestThreadLocal.get().fail(result.getError());
197 | break;
198 | case "skipped":
199 | if (isHookThreadLocal.get()) {
200 | ExtentService.getInstance().removeTest(stepTestThreadLocal.get());
201 | break;
202 | }
203 | boolean currentEndingEventSkipped = test.hasLog()
204 | ? test.getLogs().get(test.getLogs().size() - 1).getStatus() == Status.SKIP
205 | : false;
206 | if (result.getError() != null) {
207 | stepTestThreadLocal.get().skip(result.getError());
208 | } else if (!currentEndingEventSkipped) {
209 | String details = result.getError() == null ? "Step skipped" : result.getError().getMessage();
210 | stepTestThreadLocal.get().skip(details);
211 | }
212 | break;
213 | case "passed":
214 | if (stepTestThreadLocal.get() != null) {
215 | if (isHookThreadLocal.get()) {
216 | boolean mediaLogs = !test.getLogs().stream().filter(l -> l.getMedia() != null)
217 | .collect(Collectors.toList()).isEmpty();
218 | if (!test.hasLog() && !mediaLogs)
219 | ExtentService.getInstance().removeTest(stepTestThreadLocal.get());
220 | }
221 | stepTestThreadLocal.get().pass("");
222 | }
223 | break;
224 | default:
225 | break;
226 | }
227 | }
228 |
229 | private synchronized void handleEmbed(EmbedEvent event) {
230 |
231 | String mimeType = event.getMediaType();
232 | String extension = MIME_TYPES_EXTENSIONS.get(mimeType);
233 | if (extension != null) {
234 | if (stepTestThreadLocal.get() == null) {
235 | ExtentTest t = scenarioThreadLocal.get().createNode(Asterisk.class, "Embed");
236 | stepTestThreadLocal.set(t);
237 | }
238 |
239 | String title = event.getName() == null ? "" : event.getName();
240 | if (ExtentService.isBase64ImageSrcEnabled() && mimeType.startsWith("image/")) {
241 | stepTestThreadLocal.get().info(title, MediaEntityBuilder
242 | .createScreenCaptureFromBase64String(Base64.getEncoder().encodeToString(event.getData()))
243 | .build());
244 | } else {
245 | StringBuilder fileName = new StringBuilder("embedded").append(EMBEDDED_INT.incrementAndGet())
246 | .append(".").append(extension);
247 | try {
248 | URL url = toUrl(fileName.toString());
249 | writeBytesToURL(event.getData(), url);
250 | try {
251 | File file = new File(url.toURI());
252 | stepTestThreadLocal.get().info(title,
253 | MediaEntityBuilder
254 | .createScreenCaptureFromPath(
255 | ExtentService.getScreenshotReportRelatvePath() + file.getName())
256 | .build());
257 | } catch (URISyntaxException e) {
258 | e.printStackTrace();
259 | }
260 | } catch (IOException e) {
261 | e.printStackTrace();
262 | }
263 | }
264 | }
265 | }
266 |
267 | private static void writeBytesToURL(byte[] buf, URL url) throws IOException {
268 | OutputStream out = createReportFileOutputStream(url);
269 | try {
270 | out.write(buf);
271 | } catch (IOException e) {
272 | throw new IOException("Unable to write to report file item: ", e);
273 | }
274 | }
275 |
276 | private static OutputStream createReportFileOutputStream(URL url) {
277 | try {
278 | return new URLOutputStream(url);
279 | } catch (IOException | URISyntaxException e) {
280 | throw new CucumberException(e);
281 | }
282 | }
283 |
284 | private URL toUrl(String fileName) {
285 | try {
286 | URL url = Paths.get(ExtentService.getScreenshotFolderName(), fileName).toUri().toURL();
287 | return url;
288 | } catch (IOException e) {
289 | throw new CucumberException(e);
290 | }
291 | }
292 |
293 | private synchronized void handleWrite(WriteEvent event) {
294 | String text = event.getText();
295 | if (text != null && !text.isEmpty()) {
296 | stepTestThreadLocal.get().info(text);
297 | }
298 | }
299 |
300 | private void finishReport() {
301 | ExtentService.getInstance().flush();
302 | }
303 |
304 | private synchronized void handleStartOfFeature(TestCase testCase) {
305 | if (currentFeatureFile == null || !currentFeatureFile.equals(testCase.getUri())) {
306 | currentFeatureFile.set(testCase.getUri());
307 | createFeature(testCase);
308 | }
309 | }
310 |
311 | private synchronized void createFeature(TestCase testCase) {
312 | Feature feature = testSources.getFeature(testCase.getUri());
313 | try {
314 | ExtentService.getInstance().setGherkinDialect(feature.getLanguage());
315 | } catch (UnsupportedEncodingException e) {
316 | e.printStackTrace();
317 | }
318 |
319 | if (feature != null) {
320 | if (featureMap.containsKey(feature.getName())) {
321 | featureTestThreadLocal.set(featureMap.get(feature.getName()));
322 | return;
323 | }
324 | if (featureTestThreadLocal.get() != null
325 | && featureTestThreadLocal.get().getModel().getName().equals(feature.getName())) {
326 | return;
327 | }
328 | ExtentTest t = ExtentService.getInstance().createTest(
329 | com.aventstack.extentreports.gherkin.model.Feature.class, feature.getName(),
330 | feature.getDescription());
331 | featureTestThreadLocal.set(t);
332 | featureMap.put(feature.getName(), t);
333 |
334 | Set tagList = feature.getTagsList().stream().map(tag -> tag.getName()).collect(Collectors.toSet());
335 | featureTagsThreadLocal.set(tagList);
336 | }
337 | }
338 |
339 | private synchronized void handleScenarioOutline(TestCase testCase) {
340 | TestSourcesModel.AstNode astNode = testSources.getAstNode(currentFeatureFile.get(), testCase.getLine());
341 | Scenario scenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
342 |
343 | // if (scenarioDefinition.getKeyword().equals("Scenario Outline")) {
344 | if (scenarioDefinition.getExamplesCount() > 0) {
345 | if (currentScenarioOutline.get() == null
346 | || !currentScenarioOutline.get().getName().equals(scenarioDefinition.getName())) {
347 | scenarioOutlineThreadLocal.set(null);
348 | createScenarioOutline(scenarioDefinition);
349 | currentScenarioOutline.set(scenarioDefinition);
350 | }
351 | Examples examples = (Examples) astNode.parent.node;
352 | if (currentExamples.get() == null || !currentExamples.get().equals(examples)) {
353 | currentExamples.set(examples);
354 | createExamples(examples);
355 | }
356 | } else {
357 | scenarioOutlineThreadLocal.set(null);
358 | currentScenarioOutline.set(null);
359 | currentExamples.set(null);
360 | }
361 | }
362 |
363 | private synchronized void createScenarioOutline(Scenario scenarioOutline) {
364 | if (scenarioOutlineMap.containsKey(scenarioOutline.getName())) {
365 | scenarioOutlineThreadLocal.set(scenarioOutlineMap.get(scenarioOutline.getName()));
366 | return;
367 | }
368 | if (scenarioOutlineThreadLocal.get() == null) {
369 | ExtentTest t = featureTestThreadLocal.get().createNode(
370 | com.aventstack.extentreports.gherkin.model.ScenarioOutline.class, scenarioOutline.getName(),
371 | scenarioOutline.getDescription());
372 | scenarioOutlineThreadLocal.set(t);
373 | scenarioOutlineMap.put(scenarioOutline.getName(), t);
374 |
375 | /*
376 | * if (featureTagsThreadLocal.get() != null) {
377 | * featureTagsThreadLocal.get().forEach(x -> t.assignCategory(x)); }
378 | * scenarioOutline.getTagsList().stream().map(tag -> tag.getName()).forEach(c ->
379 | * t.assignCategory(c));
380 | */
381 |
382 | Set tagList = scenarioOutline.getTagsList().stream().map(tag -> tag.getName())
383 | .collect(Collectors.toSet());
384 | scenarioOutlineTagsThreadLocal.set(tagList);
385 | }
386 | }
387 |
388 | private void createExamples(Examples examples) {
389 | List rows = new ArrayList<>();
390 | rows.add(examples.getTableHeader());
391 | rows.addAll(examples.getTableBodyList());
392 | String[][] data = getTable(rows);
393 | String markup = MarkupHelper.createTable(data).getMarkup();
394 | if (examples.getName() != null && !examples.getName().isEmpty()) {
395 | markup = examples.getName() + markup;
396 | }
397 | markup = (scenarioOutlineThreadLocal.get().getModel().getDescription() == null ? ""
398 | : scenarioOutlineThreadLocal.get().getModel().getDescription() + "
") + markup;
399 | scenarioOutlineThreadLocal.get().getModel().setDescription(markup);
400 | }
401 |
402 | private String[][] getTable(List rows) {
403 | String data[][] = null;
404 | int rowSize = rows.size();
405 | for (int i = 0; i < rowSize; i++) {
406 | TableRow row = rows.get(i);
407 | List cells = row.getCellsList();
408 | int cellSize = cells.size();
409 | if (data == null) {
410 | data = new String[rowSize][cellSize];
411 | }
412 | for (int j = 0; j < cellSize; j++) {
413 | data[i][j] = cells.get(j).getValue();
414 | }
415 | }
416 | return data;
417 | }
418 |
419 | private synchronized void createTestCase(TestCase testCase) {
420 | TestSourcesModel.AstNode astNode = testSources.getAstNode(currentFeatureFile.get(), testCase.getLine());
421 | if (astNode != null) {
422 | Scenario scenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
423 | ExtentTest parent = scenarioOutlineThreadLocal.get() != null ? scenarioOutlineThreadLocal.get()
424 | : featureTestThreadLocal.get();
425 | ExtentTest t = parent.createNode(com.aventstack.extentreports.gherkin.model.Scenario.class,
426 | testCase.getName(), scenarioDefinition.getDescription());
427 | scenarioThreadLocal.set(t);
428 | }
429 | if (!testCase.getTags().isEmpty()) {
430 | // testCase.getTags().forEach(x -> scenarioThreadLocal.get().assignCategory(x));
431 | updateCategoryAndDeviceAndAuthor(testCase.getTags());
432 | }
433 | if (featureTagsThreadLocal.get() != null) {
434 | // featureTagsThreadLocal.get().forEach(x ->
435 | // scenarioThreadLocal.get().assignCategory(x));
436 | updateCategoryAndDeviceAndAuthor(featureTagsThreadLocal.get());
437 | }
438 |
439 | Test parent = scenarioThreadLocal.get().getModel().getParent();
440 | if (parent.getBddType() == ScenarioOutline.class && scenarioOutlineTagsThreadLocal.get() != null) {
441 | // scenarioOutlineTagsThreadLocal.get().forEach(x ->
442 | // scenarioThreadLocal.get().assignCategory(x));
443 | updateCategoryAndDeviceAndAuthor(scenarioOutlineTagsThreadLocal.get());
444 | }
445 | }
446 |
447 | private void updateCategoryAndDeviceAndAuthor(Collection tags) {
448 | tags.forEach(t -> {
449 | if (ExtentService.isDeviceEnabled() && isValidDeviceTag(t)) {
450 |
451 | scenarioThreadLocal.get().assignDevice(t.substring(ExtentService.getDevicePrefix().length()));
452 | } else if (ExtentService.isAuthorEnabled() && isValidAuthoTag(t)) {
453 |
454 | scenarioThreadLocal.get().assignAuthor(t.substring(ExtentService.getAuthorPrefix().length()));
455 | } else
456 | scenarioThreadLocal.get().assignCategory(t);
457 | });
458 | }
459 |
460 | private boolean isValidDeviceTag(String tag) {
461 | if (tag.startsWith(ExtentService.getDevicePrefix()) && tag.length() > ExtentService.getDevicePrefix().length())
462 | return true;
463 | return false;
464 | }
465 |
466 | private boolean isValidAuthoTag(String tag) {
467 | if (tag.startsWith(ExtentService.getAuthorPrefix()) && tag.length() > ExtentService.getAuthorPrefix().length())
468 | return true;
469 | return false;
470 | }
471 |
472 | private synchronized void createTestStep(PickleStepTestStep testStep) {
473 | String stepName = testStep.getStep().getText();
474 | TestSourcesModel.AstNode astNode = testSources.getAstNode(currentFeatureFile.get(),
475 | testStep.getStep().getLine());
476 | if (astNode != null) {
477 | Step step = (Step) astNode.node;
478 | try {
479 | String name = stepName == null || stepName.isEmpty()
480 | ? step.getText().replace("<", "<").replace(">", ">")
481 | : stepName;
482 | ExtentTest t = scenarioThreadLocal.get().createNode(new GherkinKeyword(step.getKeyword().trim()),
483 | step.getKeyword() + name, testStep.getCodeLocation());
484 | stepTestThreadLocal.set(t);
485 | } catch (ClassNotFoundException e) {
486 | e.printStackTrace();
487 | }
488 | }
489 | StepArgument argument = testStep.getStep().getArgument();
490 | if (argument != null) {
491 | if (argument instanceof DocStringArgument) {
492 | stepTestThreadLocal.get()
493 | .pass(MarkupHelper.createCodeBlock(((DocStringArgument) argument).getContent()));
494 | } else if (argument instanceof DataTableArgument) {
495 | stepTestThreadLocal.get()
496 | .pass(MarkupHelper.createTable(createDataTableList((DataTableArgument) argument)));
497 | }
498 | }
499 | }
500 |
501 | private String[][] createDataTableList(DataTableArgument dataTable) {
502 | List> cells = dataTable.cells();
503 | int rowSize = cells.size();
504 | int cellSize = cells.get(0).size();
505 | String[][] data = new String[rowSize][cellSize];
506 |
507 | for (int i = 0; i < rowSize; i++) {
508 | for (int j = 0; j < cellSize; j++)
509 | data[i][j] = cells.get(i).get(j);
510 | }
511 | return data;
512 | }
513 |
514 | // the below additions are from PR #33
515 | // https://github.com/extent-framework/extentreports-cucumber4-adapter/pull/33
516 | public static synchronized void addTestStepLog(String message) {
517 | stepTestThreadLocal.get().info(message);
518 | }
519 |
520 | public static synchronized void addTestStepScreenCaptureFromPath(String imagePath) throws IOException {
521 | stepTestThreadLocal.get().addScreenCaptureFromPath(imagePath);
522 | }
523 |
524 | public static synchronized void addTestStepScreenCaptureFromPath(String imagePath, String title)
525 | throws IOException {
526 | stepTestThreadLocal.get().addScreenCaptureFromPath(imagePath, title);
527 | }
528 |
529 | public static ExtentTest getCurrentStep() {
530 | return stepTestThreadLocal.get();
531 | }
532 |
533 | }
534 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/main/java/com/aventstack/extentreports/cucumber/adapter/TestSourcesModel.java:
--------------------------------------------------------------------------------
1 | package com.aventstack.extentreports.cucumber.adapter;
2 |
3 | import io.cucumber.gherkin.Gherkin;
4 | import io.cucumber.messages.Messages;
5 | import io.cucumber.messages.Messages.GherkinDocument;
6 | import io.cucumber.messages.Messages.GherkinDocument.Feature;
7 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Background;
8 | import io.cucumber.messages.Messages.GherkinDocument.Feature.FeatureChild;
9 | import io.cucumber.messages.Messages.GherkinDocument.Feature.FeatureChild.RuleChild;
10 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario;
11 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario.Examples;
12 | import io.cucumber.messages.Messages.GherkinDocument.Feature.Step;
13 | import io.cucumber.messages.Messages.GherkinDocument.Feature.TableRow;
14 | import io.cucumber.messages.internal.com.google.protobuf.GeneratedMessageV3;
15 | import io.cucumber.messages.internal.com.google.protobuf.Message;
16 | import io.cucumber.plugin.event.TestSourceRead;
17 |
18 | import java.io.File;
19 | import java.net.URI;
20 | import java.net.URISyntaxException;
21 | import java.util.HashMap;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.UUID;
25 |
26 | import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope;
27 | import static java.util.Collections.singletonList;
28 | import static java.util.stream.Collectors.toList;
29 |
30 | final class TestSourcesModel {
31 |
32 | private final Map pathToReadEventMap = new HashMap<>();
33 | private final Map pathToAstMap = new HashMap<>();
34 | private final Map> pathToNodeMap = new HashMap<>();
35 |
36 | static Scenario getScenarioDefinition(AstNode astNode) {
37 | AstNode candidate = astNode;
38 | while (candidate != null && !(candidate.node instanceof Scenario)) {
39 | candidate = candidate.parent;
40 | }
41 | return candidate == null ? null : (Scenario) candidate.node;
42 | }
43 |
44 | static boolean isBackgroundStep(AstNode astNode) {
45 | return astNode.parent.node instanceof Background;
46 | }
47 |
48 | static String calculateId(AstNode astNode) {
49 | GeneratedMessageV3 node = astNode.node;
50 | if (node instanceof Scenario) {
51 | return calculateId(astNode.parent) + ";" + convertToId(((Scenario) node).getName());
52 | }
53 | if (node instanceof ExamplesRowWrapperNode) {
54 | return calculateId(astNode.parent) + ";" + (((ExamplesRowWrapperNode) node).bodyRowIndex + 2);
55 | }
56 | if (node instanceof TableRow) {
57 | return calculateId(astNode.parent) + ";" + 1;
58 | }
59 | if (node instanceof Examples) {
60 | return calculateId(astNode.parent) + ";" + convertToId(((Examples) node).getName());
61 | }
62 | if (node instanceof Feature) {
63 | return convertToId(((Feature) node).getName());
64 | }
65 | return "";
66 | }
67 |
68 | static String convertToId(String name) {
69 | return name.replaceAll("[\\s'_,!]", "-").toLowerCase();
70 | }
71 |
72 | static URI relativize(URI uri) {
73 | if (!"file".equals(uri.getScheme())) {
74 | return uri;
75 | }
76 | if (!uri.isAbsolute()) {
77 | return uri;
78 | }
79 |
80 | try {
81 | URI root = new File("").toURI();
82 | URI relative = root.relativize(uri);
83 | // Scheme is lost by relativize
84 | return new URI("file", relative.getSchemeSpecificPart(), relative.getFragment());
85 | } catch (URISyntaxException e) {
86 | throw new IllegalArgumentException(e.getMessage(), e);
87 | }
88 | }
89 |
90 | void addTestSourceReadEvent(URI path, TestSourceRead event) {
91 | pathToReadEventMap.put(path, event);
92 | }
93 |
94 | Feature getFeature(URI path) {
95 | if (!pathToAstMap.containsKey(path)) {
96 | parseGherkinSource(path);
97 | }
98 | if (pathToAstMap.containsKey(path)) {
99 | return pathToAstMap.get(path).getFeature();
100 | }
101 | return null;
102 | }
103 |
104 | private void parseGherkinSource(URI path) {
105 | if (!pathToReadEventMap.containsKey(path)) {
106 | return;
107 | }
108 | String source = pathToReadEventMap.get(path).getSource();
109 |
110 | List sources = singletonList(makeSourceEnvelope(source, path.toString()));
111 |
112 | List envelopes = Gherkin
113 | .fromSources(sources, true, true, true, () -> String.valueOf(UUID.randomUUID())).collect(toList());
114 |
115 | GherkinDocument gherkinDocument = envelopes.stream().filter(Messages.Envelope::hasGherkinDocument)
116 | .map(Messages.Envelope::getGherkinDocument).findFirst().orElse(null);
117 |
118 | pathToAstMap.put(path, gherkinDocument);
119 | Map nodeMap = new HashMap<>();
120 | AstNode currentParent = new AstNode(gherkinDocument.getFeature(), null);
121 | for (FeatureChild child : gherkinDocument.getFeature().getChildrenList()) {
122 | processFeatureDefinition(nodeMap, child, currentParent);
123 | }
124 | pathToNodeMap.put(path, nodeMap);
125 |
126 | }
127 |
128 | private void processFeatureDefinition(Map nodeMap, FeatureChild child, AstNode currentParent) {
129 | if (child.hasBackground()) {
130 | processBackgroundDefinition(nodeMap, child.getBackground(), currentParent);
131 | } else if (child.hasScenario()) {
132 | processScenarioDefinition(nodeMap, child.getScenario(), currentParent);
133 | } else if (child.hasRule()) {
134 | AstNode childNode = new AstNode(child.getRule(), currentParent);
135 | nodeMap.put(child.getRule().getLocation().getLine(), childNode);
136 | for (RuleChild ruleChild : child.getRule().getChildrenList()) {
137 | processRuleDefinition(nodeMap, ruleChild, childNode);
138 | }
139 | }
140 | }
141 |
142 | private void processBackgroundDefinition(Map nodeMap, Background background,
143 | AstNode currentParent) {
144 | AstNode childNode = new AstNode(background, currentParent);
145 | nodeMap.put(background.getLocation().getLine(), childNode);
146 | for (Step step : background.getStepsList()) {
147 | nodeMap.put(step.getLocation().getLine(), new AstNode(step, childNode));
148 | }
149 | }
150 |
151 | private void processScenarioDefinition(Map nodeMap, Scenario child, AstNode currentParent) {
152 | AstNode childNode = new AstNode(child, currentParent);
153 | nodeMap.put(child.getLocation().getLine(), childNode);
154 | for (Step step : child.getStepsList()) {
155 | nodeMap.put(step.getLocation().getLine(), new AstNode(step, childNode));
156 | }
157 | if (child.getExamplesCount() > 0) {
158 | processScenarioOutlineExamples(nodeMap, child, childNode);
159 | }
160 | }
161 |
162 | private void processRuleDefinition(Map nodeMap, RuleChild child, AstNode currentParent) {
163 | if (child.hasBackground()) {
164 | processBackgroundDefinition(nodeMap, child.getBackground(), currentParent);
165 | } else if (child.hasScenario()) {
166 | processScenarioDefinition(nodeMap, child.getScenario(), currentParent);
167 | }
168 | }
169 |
170 | private void processScenarioOutlineExamples(Map nodeMap, Scenario scenarioOutline,
171 | AstNode parent) {
172 | for (Examples examples : scenarioOutline.getExamplesList()) {
173 | AstNode examplesNode = new AstNode(examples, parent);
174 | TableRow headerRow = examples.getTableHeader();
175 | AstNode headerNode = new AstNode(headerRow, examplesNode);
176 | nodeMap.put(headerRow.getLocation().getLine(), headerNode);
177 | for (int i = 0; i < examples.getTableBodyCount(); ++i) {
178 | TableRow examplesRow = examples.getTableBody(i);
179 | GeneratedMessageV3 rowNode = new ExamplesRowWrapperNode(examplesRow, i);
180 | AstNode expandedScenarioNode = new AstNode(rowNode, examplesNode);
181 | nodeMap.put(examplesRow.getLocation().getLine(), expandedScenarioNode);
182 | }
183 | }
184 | }
185 |
186 | AstNode getAstNode(URI path, int line) {
187 | if (!pathToNodeMap.containsKey(path)) {
188 | parseGherkinSource(path);
189 | }
190 | if (pathToNodeMap.containsKey(path)) {
191 | return pathToNodeMap.get(path).get(line);
192 | }
193 | return null;
194 | }
195 |
196 | boolean hasBackground(URI path, int line) {
197 | if (!pathToNodeMap.containsKey(path)) {
198 | parseGherkinSource(path);
199 | }
200 | if (pathToNodeMap.containsKey(path)) {
201 | AstNode astNode = pathToNodeMap.get(path).get(line);
202 | return getBackgroundForTestCase(astNode) != null;
203 | }
204 | return false;
205 | }
206 |
207 | static Background getBackgroundForTestCase(AstNode astNode) {
208 | Feature feature = getFeatureForTestCase(astNode);
209 | return feature.getChildrenList().stream().filter(FeatureChild::hasBackground).map(FeatureChild::getBackground)
210 | .findFirst().orElse(null);
211 | }
212 |
213 | private static Feature getFeatureForTestCase(AstNode astNode) {
214 | while (astNode.parent != null) {
215 | astNode = astNode.parent;
216 | }
217 | return (Feature) astNode.node;
218 | }
219 |
220 | static class ExamplesRowWrapperNode extends GeneratedMessageV3 {
221 |
222 | final int bodyRowIndex;
223 |
224 | ExamplesRowWrapperNode(GeneratedMessageV3 examplesRow, int bodyRowIndex) {
225 | this.bodyRowIndex = bodyRowIndex;
226 | }
227 |
228 | @Override
229 | protected FieldAccessorTable internalGetFieldAccessorTable() {
230 | throw new UnsupportedOperationException("not implemented");
231 | }
232 |
233 | @Override
234 | protected Message.Builder newBuilderForType(BuilderParent builderParent) {
235 | throw new UnsupportedOperationException("not implemented");
236 | }
237 |
238 | @Override
239 | public Message.Builder newBuilderForType() {
240 | throw new UnsupportedOperationException("not implemented");
241 | }
242 |
243 | @Override
244 | public Message.Builder toBuilder() {
245 | throw new UnsupportedOperationException("not implemented");
246 | }
247 |
248 | @Override
249 | public Message getDefaultInstanceForType() {
250 | throw new UnsupportedOperationException("not implemented");
251 | }
252 |
253 | }
254 |
255 | static class AstNode {
256 |
257 | final GeneratedMessageV3 node;
258 | final AstNode parent;
259 |
260 | AstNode(GeneratedMessageV3 node, AstNode parent) {
261 | this.node = node;
262 | this.parent = parent;
263 | }
264 |
265 | }
266 |
267 | }
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/main/java/com/aventstack/extentreports/cucumber/adapter/URLOutputStream.java:
--------------------------------------------------------------------------------
1 | package com.aventstack.extentreports.cucumber.adapter;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStream;
10 | import java.net.HttpURLConnection;
11 | import java.net.URISyntaxException;
12 | import java.net.URL;
13 | import java.util.Collections;
14 | import java.util.Map;
15 | import java.util.stream.Collectors;
16 |
17 | import static java.nio.charset.StandardCharsets.UTF_8;
18 | import io.cucumber.messages.internal.com.google.gson.Gson;
19 |
20 | /**
21 | * A stream that can write to both file and http URLs. If it's a file URL,
22 | * writes with a {@link java.io.FileOutputStream}, if it's a http or https URL,
23 | * writes with a HTTP PUT (by default) or with the specified method.
24 | */
25 | class URLOutputStream extends OutputStream {
26 | private final URL url;
27 | private final String method;
28 | private final int expectedResponseCode;
29 | private final OutputStream out;
30 | private final HttpURLConnection urlConnection;
31 |
32 | URLOutputStream(URL url) throws IOException, URISyntaxException {
33 | this(url, "PUT", Collections.emptyMap(), 200);
34 | }
35 |
36 | private URLOutputStream(URL url, String method, Map headers, int expectedResponseCode)
37 | throws IOException, URISyntaxException {
38 | this.url = url;
39 | this.method = method;
40 | this.expectedResponseCode = expectedResponseCode;
41 | if (url.getProtocol().equals("file")) {
42 | // File file = new File(url.getFile());
43 | File file = new File(url.toURI().getPath());
44 | ensureParentDirExists(file);
45 | out = new FileOutputStream(file);
46 | urlConnection = null;
47 | } else if (url.getProtocol().startsWith("http")) {
48 | urlConnection = (HttpURLConnection) url.openConnection();
49 | urlConnection.setRequestMethod(method);
50 | urlConnection.setDoOutput(true);
51 | for (Map.Entry header : headers.entrySet()) {
52 | urlConnection.setRequestProperty(header.getKey(), header.getValue());
53 | }
54 | out = urlConnection.getOutputStream();
55 | } else {
56 | throw new IllegalArgumentException("URL Scheme must be one of file,http,https. " + url.toExternalForm());
57 | }
58 | }
59 |
60 | private void ensureParentDirExists(File file) throws IOException {
61 | if (file.getParentFile() != null && !file.getParentFile().isDirectory()) {
62 | boolean ok = file.getParentFile().mkdirs() || file.getParentFile().isDirectory();
63 | if (!ok) {
64 | throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath());
65 | }
66 | }
67 | }
68 |
69 | @Override
70 | public void write(byte[] buffer, int offset, int count) throws IOException {
71 | out.write(buffer, offset, count);
72 | }
73 |
74 | @Override
75 | public void write(byte[] buffer) throws IOException {
76 | out.write(buffer);
77 | }
78 |
79 | @Override
80 | public void write(int b) throws IOException {
81 | out.write(b);
82 | }
83 |
84 | @Override
85 | public void flush() throws IOException {
86 | out.flush();
87 | }
88 |
89 | @Override
90 | public void close() throws IOException {
91 | try {
92 | if (urlConnection == null) {
93 | return;
94 | }
95 |
96 | int responseCode = urlConnection.getResponseCode();
97 | if (responseCode == expectedResponseCode) {
98 | return;
99 | }
100 |
101 | try {
102 | urlConnection.getInputStream().close();
103 | throw new IOException(
104 | String.format("Expected response code: %d. Got: %d", expectedResponseCode, responseCode));
105 | } catch (IOException expected) {
106 | InputStream errorStream = urlConnection.getErrorStream();
107 | if (errorStream != null) {
108 | throw createResponseException(responseCode, expected, errorStream);
109 | } else {
110 | throw expected;
111 | }
112 | }
113 | } finally {
114 | out.close();
115 | }
116 | }
117 |
118 | private ResponseException createResponseException(int responseCode, IOException expected, InputStream errorStream)
119 | throws IOException {
120 | try (BufferedReader br = new BufferedReader(new InputStreamReader(errorStream, UTF_8))) {
121 | String responseBody = br.lines().collect(Collectors.joining(System.lineSeparator()));
122 | String contentType = urlConnection.getHeaderField("Content-Type");
123 | if (contentType == null) {
124 | contentType = "text/plain";
125 | }
126 | return new ResponseException(responseBody, expected, responseCode, contentType);
127 | }
128 | }
129 |
130 | class ResponseException extends IOException {
131 | private static final long serialVersionUID = -1643050449805097598L;
132 | private final Gson gson = new Gson();
133 | private final int responseCode;
134 | private final String contentType;
135 |
136 | public ResponseException(String responseBody, IOException cause, int responseCode, String contentType) {
137 | super(responseBody, cause);
138 | this.responseCode = responseCode;
139 | this.contentType = contentType;
140 | }
141 |
142 | @Override
143 | public String getMessage() {
144 | if (contentType.equals("application/json")) {
145 | Map, ?> map = gson.fromJson(super.getMessage(), Map.class);
146 | if (map.containsKey("error")) {
147 | return getMessage0(map.get("error").toString());
148 | } else {
149 | return getMessage0(super.getMessage());
150 | }
151 | } else {
152 | return getMessage0(super.getMessage());
153 | }
154 | }
155 |
156 | private String getMessage0(String message) {
157 | return String.format("%s %s\nHTTP %d\n%s", method, url, responseCode, message);
158 | }
159 | }
160 | }
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/main/java/com/aventstack/extentreports/service/ExtentService.java:
--------------------------------------------------------------------------------
1 | package com.aventstack.extentreports.service;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.Serializable;
8 | import java.nio.file.Paths;
9 | import java.time.LocalDateTime;
10 | import java.time.format.DateTimeFormatter;
11 | import java.util.Arrays;
12 | import java.util.List;
13 | import java.util.Optional;
14 | import java.util.Properties;
15 | import java.util.stream.Collectors;
16 |
17 | import com.aventstack.extentreports.ExtentReports;
18 | import com.aventstack.extentreports.Status;
19 | import com.aventstack.extentreports.observer.ExtentObserver;
20 | import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
21 | import com.aventstack.extentreports.reporter.ExtentKlovReporter;
22 | import com.aventstack.extentreports.reporter.ExtentSparkReporter;
23 | import com.aventstack.extentreports.reporter.JsonFormatter;
24 | import com.aventstack.extentreports.reporter.ReporterConfigurable;
25 | import com.aventstack.extentreports.reporter.ReporterFilterable;
26 | import com.aventstack.extentreports.reporter.configuration.ViewName;
27 |
28 | import tech.grasshopper.pdf.extent.ExtentPDFCucumberReporter;
29 | import tech.grasshopper.pdf.extent.processor.MediaProcessor;
30 | import tech.grasshopper.pdf.section.details.executable.MediaCleanup.CleanupType;
31 | import tech.grasshopper.pdf.section.details.executable.MediaCleanup.MediaCleanupOption;
32 | import tech.grasshopper.reporter.ExtentExcelCucumberReporter;
33 |
34 | public class ExtentService implements Serializable {
35 |
36 | private static final long serialVersionUID = -5008231199972325650L;
37 |
38 | private static Properties properties;
39 |
40 | public static synchronized ExtentReports getInstance() {
41 | return ExtentReportsLoader.INSTANCE;
42 | }
43 |
44 | public static Object getProperty(String key) {
45 | String sys = System.getProperty(key);
46 | return sys == null ? (properties == null ? null : properties.get(key)) : sys;
47 | }
48 |
49 | public static Object getPropertyOrDefault(String key, Object defaultValue) {
50 | Object value = getProperty(key);
51 | return value == null ? defaultValue : value;
52 | }
53 |
54 | public static String getScreenshotFolderName() {
55 | return ExtentReportsLoader.SCREENSHOT_FOLDER_NAME;
56 | }
57 |
58 | public static String getScreenshotReportRelatvePath() {
59 | return ExtentReportsLoader.SCREENSHOT_FOLDER_REPORT_RELATIVE_PATH;
60 | }
61 |
62 | public static boolean isBase64ImageSrcEnabled() {
63 | return ExtentReportsLoader.ENABLE_BASE64_IMAGE_SRC;
64 | }
65 |
66 | public static boolean isDeviceEnabled() {
67 | return ExtentReportsLoader.IS_DEVICE_ENABLED;
68 | }
69 |
70 | public static boolean isAuthorEnabled() {
71 | return ExtentReportsLoader.IS_AUTHOR_ENABLED;
72 | }
73 |
74 | public static String getDevicePrefix() {
75 | return ExtentReportsLoader.DEVICE_NAME_PREFIX;
76 | }
77 |
78 | public static String getAuthorPrefix() {
79 | return ExtentReportsLoader.AUTHOR_NAME_PREFIX;
80 | }
81 |
82 | @SuppressWarnings("unused")
83 | private ExtentReports readResolve() {
84 | return ExtentReportsLoader.INSTANCE;
85 | }
86 |
87 | private static class ExtentReportsLoader {
88 |
89 | private static final ExtentReports INSTANCE = new ExtentReports();
90 | private static final String[] DEFAULT_SETUP_PATH = new String[] { "extent.properties",
91 | "com/aventstack/adapter/extent.properties" };
92 |
93 | private static final String SYS_INFO_MARKER = "systeminfo.";
94 | private static final String OUTPUT_PATH = "test-output/";
95 | private static final String EXTENT_REPORTER = "extent.reporter";
96 | private static final String START = "start";
97 | private static final String CONFIG = "config";
98 | private static final String OUT = "out";
99 | private static final String VIEW_ORDER = "vieworder";
100 | private static final String STATUS_FILTER = "statusfilter";
101 | private static final String BASE64_IMAGE_SRC = "base64imagesrc";
102 | private static final String ENABLE_DEVICE = "enable.device";
103 | private static final String ENABLE_AUTHOR = "enable.author";
104 | private static final String PREFIX_DEVICE = "prefix.device";
105 | private static final String PREFIX_AUTHOR = "prefix.author";
106 | private static final String DELIM = ".";
107 |
108 | private static final String KLOV = "klov";
109 | private static final String SPARK = "spark";
110 | private static final String JSONF = "json";
111 | private static final String PDF = "pdf";
112 | private static final String HTML = "html";
113 | private static final String EXCEL = "excel";
114 |
115 | private static final String INIT_KLOV_KEY = EXTENT_REPORTER + DELIM + KLOV + DELIM + START;
116 | private static final String INIT_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + START;
117 | private static final String INIT_JSONF_KEY = EXTENT_REPORTER + DELIM + JSONF + DELIM + START;
118 | private static final String INIT_PDF_KEY = EXTENT_REPORTER + DELIM + PDF + DELIM + START;
119 | private static final String INIT_HTML_KEY = EXTENT_REPORTER + DELIM + HTML + DELIM + START;
120 | private static final String INIT_EXCEL_KEY = EXTENT_REPORTER + DELIM + EXCEL + DELIM + START;
121 |
122 | private static final String CONFIG_KLOV_KEY = EXTENT_REPORTER + DELIM + KLOV + DELIM + CONFIG;
123 | private static final String CONFIG_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + CONFIG;
124 | private static final String CONFIG_HTML_KEY = EXTENT_REPORTER + DELIM + HTML + DELIM + CONFIG;
125 |
126 | private static final String OUT_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + OUT;
127 | private static final String OUT_JSONF_KEY = EXTENT_REPORTER + DELIM + JSONF + DELIM + OUT;
128 | private static final String OUT_PDF_KEY = EXTENT_REPORTER + DELIM + PDF + DELIM + OUT;
129 | private static final String OUT_HTML_KEY = EXTENT_REPORTER + DELIM + HTML + DELIM + OUT;
130 | private static final String OUT_EXCEL_KEY = EXTENT_REPORTER + DELIM + EXCEL + DELIM + OUT;
131 |
132 | private static final String VIEW_ORDER_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + VIEW_ORDER;
133 | private static final String BASE64_IMAGE_SRC_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM
134 | + BASE64_IMAGE_SRC;
135 |
136 | private static final String DEVICE_ENABLE_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + ENABLE_DEVICE;
137 | private static final String AUTHOR_ENABLE_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + ENABLE_AUTHOR;
138 | private static final String DEVICE_PREFIX_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + PREFIX_DEVICE;
139 | private static final String AUTHOR_PREFIX_SPARK_KEY = EXTENT_REPORTER + DELIM + SPARK + DELIM + PREFIX_AUTHOR;
140 |
141 | private static boolean ENABLE_BASE64_IMAGE_SRC = false;
142 |
143 | // Use below for both Spark & Pdf reporters
144 | private static final String STATUS_FILTER_KEY = EXTENT_REPORTER + DELIM + STATUS_FILTER;
145 |
146 | private static String SCREENSHOT_FOLDER_NAME;
147 | private static String SCREENSHOT_FOLDER_REPORT_RELATIVE_PATH;
148 | private static final String DEFAULT_SCREENSHOT_FOLDER_NAME = "test-output/";
149 |
150 | private static final String SCREENSHOT_DIR_PROPERTY = "screenshot.dir";
151 | private static final String SCREENSHOT_REL_PATH_PROPERTY = "screenshot.rel.path";
152 |
153 | private static final String REPORTS_BASEFOLDER = "basefolder";
154 | private static final String REPORTS_BASEFOLDER_NAME = REPORTS_BASEFOLDER + DELIM + "name";
155 | private static final String REPORTS_BASEFOLDER_DATETIMEPATTERN = REPORTS_BASEFOLDER + DELIM + "datetimepattern";
156 | private static final String REPORTS_BASEFOLDER_ENABLEDELIMITER = REPORTS_BASEFOLDER + DELIM
157 | + "enable.delimiter";
158 | private static final String REPORTS_BASEFOLDER_DELIMITER = REPORTS_BASEFOLDER + DELIM + "delimiter";
159 | private static final LocalDateTime FOLDER_CURRENT_TIMESTAMP = LocalDateTime.now();
160 |
161 | private static boolean IS_DEVICE_ENABLED = false;
162 | private static boolean IS_AUTHOR_ENABLED = false;
163 | private static String DEVICE_NAME_PREFIX;
164 | private static String AUTHOR_NAME_PREFIX;
165 |
166 | private static final String DEFAULT_DEVICE_PREFIX = "@dev_";
167 | private static final String DEFAULT_AUTHOR_PREFIX = "@aut_";
168 |
169 | static {
170 | createViaProperties();
171 | createViaSystem();
172 | configureScreenshotProperties();
173 | configureDeviceAndAuthorProperties();
174 | }
175 |
176 | private static void createViaProperties() {
177 |
178 | ClassLoader loader = ExtentReportsLoader.class.getClassLoader();
179 | Optional is = Arrays.stream(DEFAULT_SETUP_PATH).map(x -> loader.getResourceAsStream(x))
180 | .filter(x -> x != null).findFirst();
181 | if (is.isPresent()) {
182 | Properties properties = new Properties();
183 | try {
184 | properties.load(is.get());
185 | ExtentService.properties = properties;
186 |
187 | if (properties.containsKey(INIT_KLOV_KEY)
188 | && "true".equals(String.valueOf(properties.get(INIT_KLOV_KEY))))
189 | initKlov(properties);
190 |
191 | if (properties.containsKey(INIT_SPARK_KEY)
192 | && "true".equals(String.valueOf(properties.get(INIT_SPARK_KEY))))
193 | initSpark(properties);
194 |
195 | if (properties.containsKey(INIT_JSONF_KEY)
196 | && "true".equals(String.valueOf(properties.get(INIT_JSONF_KEY))))
197 | initJsonf(properties);
198 |
199 | if (properties.containsKey(INIT_PDF_KEY)
200 | && "true".equals(String.valueOf(properties.get(INIT_PDF_KEY))))
201 | initPdf(properties);
202 |
203 | if (properties.containsKey(INIT_HTML_KEY)
204 | && "true".equals(String.valueOf(properties.get(INIT_HTML_KEY))))
205 | initHtml(properties);
206 |
207 | if (properties.containsKey(INIT_EXCEL_KEY)
208 | && "true".equals(String.valueOf(properties.get(INIT_EXCEL_KEY))))
209 | initExcel(properties);
210 |
211 | addSystemInfo(properties);
212 | } catch (Exception e) {
213 | e.printStackTrace();
214 | }
215 | }
216 | }
217 |
218 | private static void createViaSystem() {
219 |
220 | if ("true".equals(System.getProperty(INIT_KLOV_KEY)))
221 | initKlov(null);
222 |
223 | if ("true".equals(System.getProperty(INIT_SPARK_KEY)))
224 | initSpark(null);
225 |
226 | if ("true".equals(System.getProperty(INIT_JSONF_KEY)))
227 | initJsonf(null);
228 |
229 | if ("true".equals(System.getProperty(INIT_PDF_KEY)))
230 | initPdf(null);
231 |
232 | if ("true".equals(System.getProperty(INIT_HTML_KEY)))
233 | initHtml(null);
234 |
235 | if ("true".equals(System.getProperty(INIT_EXCEL_KEY)))
236 | initExcel(null);
237 |
238 | addSystemInfo(System.getProperties());
239 | }
240 |
241 | private static String getBaseFolderName() {
242 | String folderpattern = "";
243 | Object baseFolderPrefix = getProperty(REPORTS_BASEFOLDER_NAME);
244 | Object baseFolderPatternSuffix = getProperty(REPORTS_BASEFOLDER_DATETIMEPATTERN);
245 | String enableDelimiter = String.valueOf(getPropertyOrDefault(REPORTS_BASEFOLDER_ENABLEDELIMITER, "true"));
246 | String delimiter = String.valueOf(getPropertyOrDefault(REPORTS_BASEFOLDER_DELIMITER, " "));
247 |
248 | if (enableDelimiter.equalsIgnoreCase("false"))
249 | delimiter = "";
250 |
251 | if (baseFolderPrefix != null && !String.valueOf(baseFolderPrefix).isEmpty()
252 | && baseFolderPatternSuffix != null && !String.valueOf(baseFolderPatternSuffix).isEmpty()) {
253 | DateTimeFormatter folderSuffix = DateTimeFormatter.ofPattern(String.valueOf(baseFolderPatternSuffix));
254 | folderpattern = baseFolderPrefix + delimiter + folderSuffix.format(FOLDER_CURRENT_TIMESTAMP) + "/";
255 | }
256 | return folderpattern;
257 | }
258 |
259 | private static String getOutputPath(Properties properties, String key) {
260 | String out;
261 | if (properties != null && properties.get(key) != null)
262 | out = String.valueOf(properties.get(key));
263 | else
264 | out = System.getProperty(key);
265 | out = out == null || out.equals("null") || out.isEmpty() ? OUTPUT_PATH + key.split("\\.")[2] + "/" : out;
266 | return getBaseFolderName() + out;
267 | }
268 |
269 | private static void configureScreenshotProperties() {
270 | Object property = getProperty(SCREENSHOT_DIR_PROPERTY);
271 | SCREENSHOT_FOLDER_NAME = property == null || String.valueOf(property).isEmpty()
272 | ? DEFAULT_SCREENSHOT_FOLDER_NAME
273 | : String.valueOf(property);
274 | SCREENSHOT_FOLDER_NAME = getBaseFolderName() + SCREENSHOT_FOLDER_NAME;
275 |
276 | property = getProperty(SCREENSHOT_REL_PATH_PROPERTY);
277 | SCREENSHOT_FOLDER_REPORT_RELATIVE_PATH = property == null || String.valueOf(property).isEmpty()
278 | ? SCREENSHOT_FOLDER_NAME
279 | : String.valueOf(property);
280 | }
281 |
282 | private static void configureDeviceAndAuthorProperties() {
283 | if ("true".equals(String.valueOf(getPropertyOrDefault(DEVICE_ENABLE_SPARK_KEY, "false"))))
284 | IS_DEVICE_ENABLED = true;
285 | if ("true".equals(String.valueOf(getPropertyOrDefault(AUTHOR_ENABLE_SPARK_KEY, "false"))))
286 | IS_AUTHOR_ENABLED = true;
287 |
288 | if (IS_DEVICE_ENABLED) {
289 | String property = String.valueOf(getPropertyOrDefault(DEVICE_PREFIX_SPARK_KEY, DEFAULT_DEVICE_PREFIX));
290 | if (!property.isEmpty())
291 | DEVICE_NAME_PREFIX = property;
292 | }
293 |
294 | if (IS_AUTHOR_ENABLED) {
295 | String property = String.valueOf(getPropertyOrDefault(AUTHOR_PREFIX_SPARK_KEY, DEFAULT_AUTHOR_PREFIX));
296 | if (!property.isEmpty())
297 | AUTHOR_NAME_PREFIX = property;
298 | }
299 | }
300 |
301 | private static void initKlov(Properties properties) {
302 | ExtentKlovReporter klov = new ExtentKlovReporter("Default");
303 | String configPath = properties == null ? System.getProperty(CONFIG_KLOV_KEY)
304 | : String.valueOf(properties.get(CONFIG_KLOV_KEY));
305 | File f = new File(configPath);
306 | if (configPath != null && !configPath.isEmpty() && f.exists()) {
307 | // Object prop = ExtentService.getProperty("screenshot.dir");
308 | // String screenshotDir = prop == null ? "test-output/" : String.valueOf(prop);
309 | configureScreenshotProperties();
310 | String url = Paths.get(SCREENSHOT_FOLDER_NAME).toString();
311 | ExtentService.getInstance().tryResolveMediaPath(new String[] { url });
312 | try {
313 | InputStream is = new FileInputStream(f);
314 | klov.loadInitializationParams(is);
315 | INSTANCE.attachReporter(klov);
316 | } catch (IOException e) {
317 | e.printStackTrace();
318 | }
319 | }
320 | }
321 |
322 | private static void initSpark(Properties properties) {
323 | String out = getOutputPath(properties, OUT_SPARK_KEY);
324 | ExtentSparkReporter spark = new ExtentSparkReporter(out);
325 | sparkReportViewOrder(spark);
326 | filterReportStatus(spark);
327 | base64PngImageStyle();
328 | attach(spark, properties, CONFIG_SPARK_KEY);
329 | }
330 |
331 | private static void initHtml(Properties properties) {
332 | String out = getOutputPath(properties, OUT_HTML_KEY);
333 | ExtentHtmlReporter html = new ExtentHtmlReporter(out);
334 | filterReportStatus(html);
335 | base64PngImageStyle();
336 | attach(html, properties, CONFIG_HTML_KEY);
337 | }
338 |
339 | private static void initExcel(Properties properties) {
340 | String out = getOutputPath(properties, OUT_EXCEL_KEY);
341 | ExtentExcelCucumberReporter excel = new ExtentExcelCucumberReporter(out);
342 | INSTANCE.attachReporter(excel);
343 | }
344 |
345 | private static void filterReportStatus(ReporterFilterable> reporter) {
346 | try {
347 | if (getProperty(STATUS_FILTER_KEY) == null)
348 | return;
349 |
350 | List statuses = Arrays.stream(String.valueOf(getProperty(STATUS_FILTER_KEY)).split(","))
351 | .map(s -> convertToStatus(s)).collect(Collectors.toList());
352 | reporter.filter().statusFilter().as(statuses);
353 | } catch (Exception e) {
354 | // Do nothing. Uses no filter.
355 | }
356 | }
357 |
358 | private static void sparkReportViewOrder(ExtentSparkReporter spark) {
359 | try {
360 | List viewOrder = Arrays.stream(String.valueOf(getProperty(VIEW_ORDER_SPARK_KEY)).split(","))
361 | .map(v -> ViewName.valueOf(v.toUpperCase())).collect(Collectors.toList());
362 | spark.viewConfigurer().viewOrder().as(viewOrder).apply();
363 | } catch (Exception e) {
364 | // Do nothing. Use default order.
365 | }
366 | }
367 |
368 | private static void base64PngImageStyle() {
369 | if ("true".equals(String.valueOf(properties.getOrDefault(BASE64_IMAGE_SRC_SPARK_KEY, "false")))) {
370 | ENABLE_BASE64_IMAGE_SRC = true;
371 | }
372 | }
373 |
374 | private static void initJsonf(Properties properties) {
375 | String out = getOutputPath(properties, OUT_JSONF_KEY);
376 | JsonFormatter jsonf = new JsonFormatter(out);
377 | INSTANCE.attachReporter(jsonf);
378 | }
379 |
380 | private static void initPdf(Properties properties) {
381 | String out = getOutputPath(properties, OUT_PDF_KEY);
382 | configureScreenshotProperties();
383 | MediaCleanupOption mediaCleanup = MediaCleanupOption.builder().cleanUpType(CleanupType.PATTERN)
384 | .pattern(MediaProcessor.EMBEDDED_PREFIX + ".*").build();
385 | ExtentPDFCucumberReporter pdf = new ExtentPDFCucumberReporter(out, SCREENSHOT_FOLDER_NAME, mediaCleanup);
386 | filterReportStatus(pdf);
387 | INSTANCE.attachReporter(pdf);
388 | }
389 |
390 | private static void attach(ReporterConfigurable r, Properties properties, String configKey) {
391 | Object configPath = properties == null ? System.getProperty(configKey) : properties.get(configKey);
392 | if (configPath != null && !String.valueOf(configPath).isEmpty())
393 | try {
394 | r.loadXMLConfig(String.valueOf(configPath));
395 | } catch (IOException e) {
396 | e.printStackTrace();
397 | }
398 | INSTANCE.attachReporter((ExtentObserver>) r);
399 | }
400 |
401 | private static void addSystemInfo(Properties properties) {
402 | properties.forEach((k, v) -> {
403 | String key = String.valueOf(k);
404 | if (key.startsWith(SYS_INFO_MARKER)) {
405 | key = key.substring(key.indexOf('.') + 1);
406 | INSTANCE.setSystemInfo(key, String.valueOf(v));
407 | }
408 | });
409 | }
410 |
411 | private static Status convertToStatus(String status) {
412 | String lowerStatus = status.toLowerCase();
413 |
414 | switch (lowerStatus) {
415 | case "info":
416 | return Status.INFO;
417 | case "pass":
418 | return Status.PASS;
419 | case "Warning":
420 | return Status.WARNING;
421 | case "skip":
422 | return Status.SKIP;
423 | case "fail":
424 | return Status.FAIL;
425 | default:
426 | throw new IllegalArgumentException();
427 | }
428 | }
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/Configurer.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import java.lang.reflect.Type;
4 |
5 | import com.fasterxml.jackson.databind.JavaType;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
8 |
9 | import io.cucumber.java.DefaultDataTableCellTransformer;
10 | import io.cucumber.java.DefaultDataTableEntryTransformer;
11 | import io.cucumber.java.DefaultParameterTransformer;
12 |
13 | public class Configurer {
14 |
15 | private final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
16 |
17 | @DefaultParameterTransformer
18 | @DefaultDataTableEntryTransformer
19 | @DefaultDataTableCellTransformer
20 | public Object defaultTransformer(Object fromValue, Type toValueType) {
21 | JavaType javaType = objectMapper.constructType(toValueType);
22 | return objectMapper.convertValue(fromValue, javaType);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/DateCalculator.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import java.util.Date;
4 |
5 | public class DateCalculator {
6 | private Date now;
7 |
8 | public DateCalculator(Date now) {
9 | this.now = now;
10 | }
11 |
12 | public String isDateInThePast(Date date) {
13 | return (date.before(now)) ? "yes" : "no";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/DateStepdefs.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import static java.text.DateFormat.MEDIUM;
4 | import static java.text.DateFormat.getDateInstance;
5 | import static java.util.Locale.ENGLISH;
6 | import static org.testng.Assert.assertEquals;
7 |
8 | import java.text.ParseException;
9 | import java.text.SimpleDateFormat;
10 | import java.util.Date;
11 |
12 | import io.cucumber.java.ParameterType;
13 | import io.cucumber.java.en.Given;
14 | import io.cucumber.java.en.Then;
15 | import io.cucumber.java.en.When;
16 |
17 |
18 | public class DateStepdefs {
19 | private String result;
20 | private DateCalculator calculator;
21 |
22 | @ParameterType(".*?")
23 | public Date isodate(String date) throws ParseException {
24 | return new SimpleDateFormat("yyyy-mm-dd").parse(date);
25 | }
26 |
27 | @Given("today is {isodate}")
28 | public void today_is(Date date) {
29 | calculator = new DateCalculator(date);
30 | }
31 |
32 | @ParameterType(".*?")
33 | public Date date(String date) throws ParseException {
34 | return getDateInstance(MEDIUM, ENGLISH).parse(date);
35 | }
36 |
37 | @When("I ask if {date} is in the past")
38 | public void I_ask_if_date_is_in_the_past(Date date) {
39 | result = calculator.isDateInThePast(date);
40 | }
41 |
42 | @Then("the result should be {string}")
43 | public void the_result_should_be(String expectedResult) {
44 | assertEquals(expectedResult, result);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/Example.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | public interface Example {
4 | }
5 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/RpnCalculator.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import java.util.Deque;
4 | import java.util.LinkedList;
5 | import java.util.List;
6 |
7 | import static java.util.Arrays.asList;
8 |
9 | public class RpnCalculator {
10 | private final Deque stack = new LinkedList();
11 | private static final List OPS = asList("-", "+", "*", "/");
12 |
13 | public void push(Object arg) {
14 | if (OPS.contains(arg)) {
15 | Number y = stack.removeLast();
16 | Number x = stack.isEmpty() ? 0 : stack.removeLast();
17 | Double val = null;
18 | if (arg.equals("-")) {
19 | val = x.doubleValue() - y.doubleValue();
20 | } else if (arg.equals("+")) {
21 | val = x.doubleValue() + y.doubleValue();
22 | } else if (arg.equals("*")) {
23 | val = x.doubleValue() * y.doubleValue();
24 | } else if (arg.equals("/")) {
25 | val = x.doubleValue() / y.doubleValue();
26 | }
27 | push(val);
28 | } else {
29 | stack.add((Number) arg);
30 | }
31 | }
32 |
33 | public void PI() {
34 | push(Math.PI);
35 | }
36 |
37 | public Number value() {
38 | return stack.getLast();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/RpnCalculatorStepdefs.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import static org.testng.Assert.assertEquals;
4 |
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import io.cucumber.java.After;
9 | import io.cucumber.java.Before;
10 | import io.cucumber.java.DataTableType;
11 | import io.cucumber.java.Scenario;
12 | import io.cucumber.java.en.Given;
13 | import io.cucumber.java.en.Then;
14 | import io.cucumber.java.en.When;
15 |
16 | public class RpnCalculatorStepdefs {
17 | private RpnCalculator calc;
18 |
19 | @Given("a calculator I just turned on")
20 | public void a_calculator_I_just_turned_on() {
21 | calc = new RpnCalculator();
22 | }
23 |
24 | @When("I add {int} and {int}")
25 | public void adding(int arg1, int arg2) {
26 | calc.push(arg1);
27 | calc.push(arg2);
28 | calc.push("+");
29 | }
30 |
31 | @Given("I press {string}")
32 | public void I_press(String what) {
33 | calc.push(what);
34 | }
35 |
36 | @Then("the result is {int}")
37 | public void the_result_is(double expected) {
38 | assertEquals(expected, calc.value());
39 | }
40 |
41 | @Before("not @foo")
42 | public void before(Scenario scenario) {
43 | scenario.log("Runs BEFORE scenarios *not* tagged with @foo");
44 | }
45 |
46 | @After("not @foo")
47 | public void after(Scenario scenario) {
48 | scenario.log("Runs AFTER scenarios *not* tagged with @foo");
49 | }
50 |
51 | @DataTableType
52 | public Entry getEntries(Map entry) {
53 | return new Entry(Integer.valueOf(entry.get("first")),
54 | Integer.valueOf(entry.get("second")),
55 | entry.get("operation"));
56 | }
57 |
58 | @Given("the previous entries:")
59 | public void thePreviousEntries(List entries) {
60 | for (Entry entry : entries) {
61 | calc.push(entry.first);
62 | calc.push(entry.second);
63 | calc.push(entry.operation);
64 | }
65 | }
66 |
67 | static final class Entry {
68 | private final Integer first;
69 | private final Integer second;
70 | private final String operation;
71 |
72 | Entry(Integer first, Integer second, String operation) {
73 | this.first = first;
74 | this.second = second;
75 | this.operation = operation;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/RunCukesTest.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import io.cucumber.testng.AbstractTestNGCucumberTests;
4 | import io.cucumber.testng.CucumberOptions;
5 |
6 | @CucumberOptions(plugin = {"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"})
7 | public class RunCukesTest extends AbstractTestNGCucumberTests {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/ScreenShotStepDefinition.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import org.openqa.selenium.OutputType;
4 | import org.openqa.selenium.TakesScreenshot;
5 | import org.openqa.selenium.WebDriver;
6 | import org.openqa.selenium.chrome.ChromeDriver;
7 |
8 | import io.cucumber.java.AfterStep;
9 | import io.cucumber.java.BeforeStep;
10 | import io.cucumber.java.Scenario;
11 | import io.cucumber.java.en.And;
12 | import io.github.bonigarcia.wdm.WebDriverManager;
13 |
14 | public class ScreenShotStepDefinition {
15 |
16 | private WebDriver driver;
17 |
18 | @And("Go to {word}")
19 | public void visitweb(String site) throws Exception {
20 | System.out.println(site);
21 | driver.get(site);
22 | Thread.sleep(5000);
23 | }
24 |
25 | @BeforeStep(value = "@website")
26 | public void beforeSite() {
27 | System.out.println("BEFORE SITE");
28 | WebDriverManager.chromedriver().setup();
29 | driver = new ChromeDriver();
30 | driver.manage().window().maximize();
31 | }
32 |
33 | @AfterStep(value = "@website")
34 | public void afterSite(Scenario scenario) {
35 | System.out.println("AFTER SITE");
36 |
37 | TakesScreenshot ts = (TakesScreenshot) driver;
38 | byte[] screenshot = ts.getScreenshotAs(OutputType.BYTES);
39 | scenario.log("this is my failure message……….");
40 | scenario.attach(screenshot, "image/png","");
41 | driver.quit();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/java/cucumber/examples/java/calculator/ShoppingStepdefs.java:
--------------------------------------------------------------------------------
1 | package cucumber.examples.java.calculator;
2 |
3 | import static org.testng.Assert.assertEquals;
4 |
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import io.cucumber.java.DataTableType;
9 | import io.cucumber.java.DocStringType;
10 | import io.cucumber.java.en.Given;
11 | import io.cucumber.java.en.Then;
12 | import io.cucumber.java.en.When;
13 |
14 | public class ShoppingStepdefs {
15 | private RpnCalculator calc = new RpnCalculator();
16 |
17 | @DataTableType
18 | public Grocery getGroceries(Map entry) {
19 | return new Grocery(entry.get("name"), new Price(Integer.parseInt(entry.get("price"))));
20 | }
21 |
22 | @Given("the following groceries:")
23 | public void the_following_groceries(List groceries) {
24 | for (Grocery grocery : groceries) {
25 | calc.push(grocery.price.value);
26 | calc.push("+");
27 | }
28 | }
29 |
30 | @When("I pay {int}")
31 | public void i_pay(int amount) {
32 | calc.push(amount);
33 | calc.push("-");
34 | }
35 |
36 | @Then("my change should be {int}")
37 | public void my_change_should_be_(int change) {
38 | assertEquals(-calc.value().intValue(), change);
39 | }
40 |
41 | @DocStringType
42 | public Speech getSpeech(String text) {
43 | return new Speech(text);
44 | }
45 |
46 | @Given("the doc string is")
47 | public void the_doc_string_is(Speech speech) {
48 | System.out.println(speech);
49 | }
50 |
51 | public static class Speech {
52 | private String text;
53 | private int lines;
54 | private int words;
55 |
56 | public Speech(String text) {
57 | this.text = text;
58 | this.lines = text.split("[\\n\\r]+").length;
59 | this.words = text.split("[\\s]+").length;
60 | }
61 | }
62 |
63 | public static class Grocery {
64 | @SuppressWarnings("unused")
65 | private String name;
66 | private Price price;
67 |
68 | Grocery(String name, Price price) {
69 | this.name = name;
70 | this.price = price;
71 | }
72 | }
73 |
74 | public static final class Price {
75 | private int value;
76 |
77 | Price(int value) {
78 | this.value = value;
79 | }
80 |
81 | static Price fromString(String value) {
82 | return new Price(Integer.parseInt(value));
83 | }
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/com/aventstack/adapter/extent.properties:
--------------------------------------------------------------------------------
1 | extent.reporter.klov.start=false
2 | extent.reporter.spark.start=true
3 | extent.reporter.json.start=true
4 | extent.reporter.pdf.start=true
5 | extent.reporter.html.start=true
6 |
7 | extent.reporter.klov.config=
8 | extent.reporter.spark.config=
9 |
10 | extent.reporter.spark.out=test-output/SparkReport/ExtentSpark.html
11 | extent.reporter.json.out=test-output/JsonReport/ExtentJson.json
12 | extent.reporter.pdf.out=test output/PdfReport/ExtentPdf.pdf
13 | extent.reporter.html.out=test-output/HtmlReport/ExtentHtml.html
14 |
15 | screenshot.dir=test-output/
16 | screenshot.rel.path=../
17 |
18 | systeminfo.os=Windows
19 | systeminfo.version=10
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/com/aventstack/adapter/html-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | dark
7 |
8 |
9 |
10 | UTF-8
11 |
12 |
13 |
14 | https
15 |
16 |
17 | HTML Extent
18 |
19 |
20 | GhChirp Report
21 |
22 |
23 | false
24 |
25 |
26 | top
27 | true
28 | true
29 | true
30 |
31 |
32 |
33 | true
34 | true
35 | true
36 | true
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/com/aventstack/adapter/klov.properties:
--------------------------------------------------------------------------------
1 | mongodb.host=localhost
2 | mongodb.port=27017
3 | mongodb.uri=
4 | klov.host=localhost
5 | klov.port=80
6 | klov.project.name=cucumber4
7 | klov.report.name=examples
8 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/com/aventstack/adapter/spark-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | dark
7 |
8 |
9 |
10 | UTF-8
11 |
12 |
13 |
14 | https
15 |
16 |
17 | Spark Extent
18 |
19 |
20 | Grasshopper Report
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/cucumber/examples/java/calculator/basic_arithmetic.feature:
--------------------------------------------------------------------------------
1 | @foo
2 | Feature: Basic Arithmetic
3 |
4 | Background: A Calculator
5 | Given a calculator I just turned on
6 |
7 | Scenario: Addition Scenario
8 | # Try to change one of the values below to provoke a failure
9 | When I add 4 and 5
10 | Then the result is 9
11 |
12 | Scenario: Another Addition
13 | # Try to change one of the values below to provoke a failure
14 | When I add 4 and 7
15 | Then the result is 11
16 |
17 | Scenario Outline: Many additions
18 | Given the previous entries:
19 | | first | second | operation |
20 | | 1 | 1 | + |
21 | | 2 | 1 | + |
22 | When I press "+"
23 | And I add and
24 | And I press "+"
25 | Then the result is
26 |
27 | Examples: Single digits
28 | | a | b | c |
29 | | 1 | 2 | 9 |
30 | | 2 | 3 | 10 |
31 |
32 | Examples: Double digits
33 | | a | b | c |
34 | | 10 | 20 | 35 |
35 | | 20 | 30 | 55 |
36 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/cucumber/examples/java/calculator/date_calculator.feature:
--------------------------------------------------------------------------------
1 | @calc
2 | Feature: Dates with different date formats
3 | This feature shows you can have different date formats, as long as you annotate the
4 | corresponding step definition method accordingly.
5 |
6 | Scenario: Determine past date
7 | Given today is 2011-01-20
8 | When I ask if Jan 19, 2011 is in the past
9 | Then the result should be "yes"
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/cucumber/examples/java/calculator/screen.feature:
--------------------------------------------------------------------------------
1 | Feature: Scenarios feature file for screenshot
2 |
3 | @website
4 | Scenario: Scenario screenshot
5 | Given Go to https://stackoverflow.com/
6 | Given Go to https://github.com/
7 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/cucumber/examples/java/calculator/shopping.feature:
--------------------------------------------------------------------------------
1 | @shop
2 | Feature: Shopping
3 |
4 | Scenario: Give correct change
5 | Given the following groceries:
6 | | name | price |
7 | | milk | 9 |
8 | | bread | 7 |
9 | | soap | 5 |
10 | When I pay 25
11 | Then my change should be 4
12 |
13 | Scenario: Doc String to Custom Object
14 | Given the doc string is
15 | """
16 | Hello there how r u?
17 |
18 | Doing great.
19 | Whats new?
20 | """
21 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/cucumber/examples/java/calculator/skipdef.feature:
--------------------------------------------------------------------------------
1 | Feature: Scenarios With No Step Definitions
2 |
3 | @skipscenario
4 | Scenario: No Step defined
5 | Given No step definition methods
6 |
--------------------------------------------------------------------------------
/extentreports-cucumber6-adapter/src/test/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grasshopper7/extentreports-cucumber6-adapter/83dad648d859c244e33fce99238c378df05987fa/extentreports-cucumber6-adapter/src/test/resources/logo.png
--------------------------------------------------------------------------------
/summary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grasshopper7/extentreports-cucumber6-adapter/83dad648d859c244e33fce99238c378df05987fa/summary.png
--------------------------------------------------------------------------------