1+ /*
2+ * (C) Copyright 2025 Boni Garcia (https://bonigarcia.github.io/)
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ *
16+ */
17+ package io .github .bonigarcia .junit .selenium ;
18+
19+ import java .lang .reflect .Field ;
20+
21+ import org .junit .jupiter .api .extension .AfterTestExecutionCallback ;
22+ import org .junit .jupiter .api .extension .BeforeAllCallback ;
23+ import org .junit .jupiter .api .extension .BeforeEachCallback ;
24+ import org .junit .jupiter .api .extension .ExtensionContext ;
25+ import org .junit .jupiter .api .extension .ExtensionContext .Store ;
26+ import org .openqa .selenium .OutputType ;
27+ import org .openqa .selenium .TakesScreenshot ;
28+ import org .openqa .selenium .WebDriver ;
29+
30+ import com .aventstack .extentreports .ExtentReports ;
31+ import com .aventstack .extentreports .ExtentTest ;
32+ import com .aventstack .extentreports .reporter .ExtentSparkReporter ;
33+
34+ public class ReportExtension implements BeforeAllCallback , BeforeEachCallback ,
35+ AfterTestExecutionCallback {
36+
37+ static final String STORE_NAME = "reports" ;
38+ static final ExtensionContext .Namespace REPORT_NAMESPACE = ExtensionContext .Namespace
39+ .create ("report-store" );
40+ ExtentReports report ;
41+ ExtentTest test ;
42+
43+ @ Override
44+ public void beforeAll (ExtensionContext context ) throws Exception {
45+ Store store = context .getRoot ().getStore (REPORT_NAMESPACE );
46+ report = store .get (STORE_NAME , ExtentReports .class );
47+
48+ if (report == null ) {
49+ report = new ExtentReports ();
50+ store .put (STORE_NAME , report );
51+
52+ Runtime .getRuntime ().addShutdownHook (new Thread (report ::flush ));
53+ }
54+
55+ ExtentSparkReporter htmlReporter = new ExtentSparkReporter (
56+ "report-junit.html" );
57+ report .attachReporter (htmlReporter );
58+ }
59+
60+ @ Override
61+ public void beforeEach (ExtensionContext context ) throws Exception {
62+ test = report .createTest (context .getDisplayName ());
63+ }
64+
65+ @ Override
66+ public void afterTestExecution (ExtensionContext context ) throws Exception {
67+ context .getTestInstance ().ifPresent (instance -> {
68+ try {
69+ Class <?> clazz = instance .getClass ();
70+ Field field = null ;
71+ while (clazz != null ) { // Seek driver in test class or parent
72+ try {
73+ field = clazz .getDeclaredField ("driver" );
74+ break ; // found it
75+ } catch (NoSuchFieldException e ) {
76+ clazz = clazz .getSuperclass (); // move up
77+ }
78+ }
79+ if (field != null ) {
80+ field .setAccessible (true );
81+ WebDriver driver = (WebDriver ) field .get (instance );
82+ String screenshot = ((TakesScreenshot ) driver )
83+ .getScreenshotAs (OutputType .BASE64 );
84+ test .addScreenCaptureFromBase64String (screenshot );
85+
86+ } else {
87+ throw new RuntimeException (
88+ "Driver not found in test class" );
89+ }
90+
91+ } catch (Exception e ) {
92+ e .printStackTrace ();
93+ }
94+ });
95+ }
96+
97+ }
0 commit comments