├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── nal
│ ├── keywords
│ ├── Browser.java
│ └── KeywordExecutor.java
│ ├── listeners
│ ├── ExtentReportListener.java
│ ├── FrameworkListener.java
│ └── TestAllureListener.java
│ └── utils
│ └── CSVReader.java
└── test
├── java
└── tests
│ └── KeywordDrivenTest.java
└── resources
├── csvs
├── home_test.csv
├── login_test.csv
└── search_test.csv
└── testrunner
└── testng.xml
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java CI with Maven
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Set up JDK 11 and Maven
17 | uses: actions/setup-java@v3
18 | with:
19 | java-version: '11'
20 | distribution: 'temurin'
21 | maven-version: '3.8.1' # Specify the desired Maven version
22 | cache: maven
23 | cache-dependency-path: 'sub-project/pom.xml' # optional
24 | - name: Build with Maven
25 | run: mvn clean install
26 |
27 | # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
28 | - name: Update dependency graph
29 | uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | allure-results/
2 | allure-report/
3 | screenshots/
4 | screenshot/
5 | test-output/
6 | build/
7 | reports/
8 | logs/
9 |
10 | opencart.log
11 | ##############################
12 | ## Java
13 | ##############################
14 | .mtj.tmp/
15 | *.class
16 | *.jar
17 | *.war
18 | *.ear
19 | *.nar
20 | hs_err_pid*
21 | activityLog.log
22 | ##############################
23 | ## Maven
24 | ##############################
25 | target/
26 | pom.xml.tag
27 | pom.xml.releaseBackup
28 | pom.xml.versionsBackup
29 | pom.xml.next
30 | pom.xml.bak
31 | release.properties
32 | dependency-reduced-pom.xml
33 | buildNumber.properties
34 | .mvn/timing.properties
35 | .mvn/wrapper/maven-wrapper.jar
36 |
37 | ##############################
38 | ## IntelliJ
39 | ##############################
40 | out/
41 | .idea/
42 | .idea_modules/
43 | *.iml
44 | *.ipr
45 | *.iws
46 | ##############################
47 | ## Eclipse
48 | ##############################
49 | .settings/
50 | bin/
51 | tmp/
52 | .metadata
53 | .classpath
54 | .project
55 | *.tmp
56 | *.bak
57 | *.swp
58 | *~.nib
59 | local.properties
60 | .loadpath
61 | .factorypath
62 |
63 | ## OS X
64 | ##############################
65 | .DS_Store
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
# Keyword Driven Testing Framework with Selenium
2 |
3 | ## Overview
4 | This project demonstrates a Keyword Driven Testing (KDT) framework implemented using Selenium WebDriver in Java. The framework allows for easy creation and execution of automated test cases using a set of keywords defined in CSV files.
5 |
6 | ## Features
7 | - Keyword-driven approach for writing test cases.
8 | - Test cases defined in CSV files for easy maintenance and readability.
9 | - Support for parallel execution of test cases.
10 | - Integration with TestNG for test execution and reporting.
11 | - Flexible and extensible architecture.
12 |
13 | ## Project Structure
14 | - `src/main/java/`: Contains the source code for the Keyword Driven Testing framework.
15 | - `src/test/java/`: Contains the test scripts written using the framework.
16 | - `src/test/resources/csvs/`: Contains the CSV files defining the test cases in the form of keywords.
17 | - `testng.xml`: TestNG configuration file for executing the tests.
18 |
19 | ## Setup Instructions
20 | 1. Clone the repository to your local machine.
21 | 2. Import the project into your preferred Java IDE (e.g., Eclipse, IntelliJ IDEA).
22 | 3. Ensure that you have the necessary dependencies configured (e.g., Selenium WebDriver, TestNG).
23 | 4. Define your test cases in CSV files located in the `src/test/resources/csvs/` directory.
24 |
25 | ## Running Tests
26 | - You can run the tests using the TestNG XML configuration file (`testng.xml`).
27 | - Execute the `testng.xml` file using your IDE or the TestNG command-line interface.
28 | - Ensure that the WebDriver instance is properly initialized and managed during test execution.
29 | - Parallel run through thread-count and parallel tags in testng.xml
30 |
31 | ## Console Output
32 | - You can see the full csv file formatted data in the console output.
33 |
34 |
35 |
36 | ## Test Reporting
37 | - TestNG generates detailed HTML reports after test execution.
38 | - The reports provide information about test results, including pass/fail status and error messages.
39 | - Integrated Extent and Allure reports as well, including pass/fail status, error messages and screenshot for failure tests.
40 |
41 | ## Information about reporting tools used in the project, such as Allure, ExtentReport.
42 |
43 | - Allure Report
44 | Allure is a flexible lightweight test report tool that not only shows a very concise representation of what have been tested in a neat web report form, but allows everyone participating in the development process to extract maximum of useful information from everyday execution of tests.
45 |
46 | - To generate Allure reports, follow these steps:
47 |
48 | - Install Allure command-line tool using the instructions provided in the Allure documentation.
49 |
50 | Execute your tests with Allure listeners attached.
51 |
52 | After the test execution is complete, generate the Allure report using the command:
53 | **allure generate --clean
54 | **
55 | - View the generated report by running:
56 | **allure open
57 | **
58 |
59 |
60 |
61 |
62 |
63 |
64 | - Extent Report
65 | ExtentReports is an open-source reporting library for Java designed for the creation of beautiful, interactive, and detailed HTML reports.
66 | - After the test execution is complete, the Extent report will be generated automatically.
67 | - View the generated Extent report in the /reports directory.
68 |
69 |
70 |
71 |
72 |
73 | ## Contributing
74 | Contributions to improve the framework or add new features are welcome! If you find any issues or have suggestions for improvement, please open an issue or submit a pull request.
75 |
76 | ## License
77 | NA
78 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 | 4.0.0
7 |
8 | KeywordDriven
9 | KeywordDriven
10 | 0.0.1-SNAPSHOT
11 |
12 | KeywordDriven
13 |
14 | http://www.example.com
15 |
16 |
17 | UTF-8
18 | 11
19 | 11
20 | 5.0.8
21 | 1.9.19
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.seleniumhq.selenium
30 | selenium-java
31 | 4.17.0
32 |
33 |
34 |
35 | org.testng
36 | testng
37 | 7.0.0
38 |
39 |
40 |
41 | com.aventstack
42 | extentreports
43 | ${extentreports-version}
44 |
45 |
46 |
47 | io.qameta.allure
48 | allure-testng
49 | 2.23.0
50 |
51 |
52 |
53 | org.aspectj
54 | aspectjweaver
55 | ${aspectj.version}
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.apache.maven.plugins
63 | maven-compiler-plugin
64 | 3.8.1
65 |
66 | 11
67 | 11
68 |
69 |
70 |
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-surefire-plugin
75 | 2.20
76 |
77 |
78 | 3
79 | true
80 |
81 | src/test/resources/testrunner/testng.xml
82 |
83 |
84 |
85 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
86 |
87 |
88 |
89 |
90 |
91 | org.aspectj
92 | aspectjweaver
93 | ${aspectj.version}
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/keywords/Browser.java:
--------------------------------------------------------------------------------
1 | package com.nal.keywords;
2 |
3 |
4 | public enum Browser {
5 | chrome,
6 | firefox,
7 | safari,
8 | edge,
9 | ie
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/keywords/KeywordExecutor.java:
--------------------------------------------------------------------------------
1 | package com.nal.keywords;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.List;
6 |
7 | import org.openqa.selenium.By;
8 | import org.openqa.selenium.NoSuchElementException;
9 | import org.openqa.selenium.OutputType;
10 | import org.openqa.selenium.TakesScreenshot;
11 | import org.openqa.selenium.WebDriver;
12 | import org.openqa.selenium.chrome.ChromeDriver;
13 | import org.openqa.selenium.chrome.ChromeOptions;
14 | import org.openqa.selenium.edge.EdgeDriver;
15 | import org.openqa.selenium.firefox.FirefoxDriver;
16 | import org.openqa.selenium.firefox.FirefoxOptions;
17 | import org.openqa.selenium.ie.InternetExplorerDriver;
18 | import org.openqa.selenium.io.FileHandler;
19 | import org.openqa.selenium.safari.SafariDriver;
20 | import org.testng.Assert;
21 |
22 | import com.nal.utils.CSVReader;
23 |
24 | import io.qameta.allure.Step;
25 |
26 | /**
27 | * @author naveenautomationlabs This class contains methods to execute keywords
28 | * defined in test steps and perform corresponding actions.
29 | */
30 | public class KeywordExecutor {
31 |
32 | /**
33 | * ThreadLocal instance to hold WebDriver instance for each thread.
34 | */
35 | public static ThreadLocal tlDriver = new ThreadLocal();
36 |
37 | /**
38 | * Executes the given keyword with the provided target and value.
39 | *
40 | * @param keyword The keyword to execute.
41 | * @param target The target element or location.
42 | * @param value The value to input or verify.
43 | */
44 | @Step("{keyword} | {target} | {value} | ")
45 | public void executeKeyword(String keyword, String target, String value) {
46 | switch (keyword) {
47 | case "OpenBrowser":
48 | try {
49 | Browser browser = Browser.valueOf(target.toLowerCase());
50 | openBrowser(browser);
51 | } catch (IllegalArgumentException e) {
52 | throw new IllegalArgumentException("Unsupported browser: " + value);
53 | }
54 | break;
55 | case "NavigateTo":
56 | navigateTo(target);
57 | break;
58 | case "Click":
59 | click(target);
60 | break;
61 | case "Type":
62 | type(target, value);
63 | break;
64 | case "VerifyText":
65 | verifyText(target, value);
66 | break;
67 | case "AssertElementPresent":
68 | assertElementPresent(target);
69 | break;
70 | case "SwitchToFrame":
71 | switchToFrame(target);
72 | break;
73 | case "SwitchToDefaultContent":
74 | switchToDefaultContent();
75 | break;
76 | // Add more cases for other keyword interpretations
77 | default:
78 | throw new IllegalArgumentException("Unsupported keyword: " + keyword);
79 | }
80 | }
81 |
82 | /**
83 | * Executes the test steps for the given test case name.
84 | *
85 | * @param testCaseName The name of the test case.
86 | * @param testSteps The list of test steps to execute.
87 | */
88 | public void executeTestSteps(String testCaseName, List testSteps) {
89 | System.out.println("Executing test case: " + testCaseName);
90 | for (String step : testSteps) {
91 | String[] parts = step.split(",");
92 | String keyword = parts[0].trim();
93 | String target = parts[1].trim();
94 | String value = "";
95 | if (parts.length == 3) {
96 | value = parts[2].trim();
97 | }
98 | executeKeyword(keyword, target, value);
99 | }
100 | }
101 |
102 | /**
103 | * Executes test cases from the given CSV file.
104 | *
105 | * @param csvFile The path to the CSV file containing test cases.
106 | */
107 | public void executeTestCasesFromCSV(String csvFile) {
108 | CSVReader csvReader = new CSVReader();
109 | csvReader.executeTestCasesFromCSV(csvFile);
110 | }
111 |
112 | /**
113 | * Asserts that the element specified by the target is present.
114 | *
115 | * @param target The target element.
116 | */
117 | private void assertElementPresent(String target) {
118 | By locator = getBy(target);
119 | boolean isElementPresent = isElementPresent(locator);
120 | Assert.assertTrue(isElementPresent, "Element is not present: " + target);
121 | }
122 |
123 | /**
124 | * Checks if the element specified by the locator is present.
125 | *
126 | * @param locator The locator of the element.
127 | * @return True if the element is present, otherwise false.
128 | */
129 | private boolean isElementPresent(By locator) {
130 | try {
131 | getDriver().findElement(locator);
132 | return true;
133 | } catch (NoSuchElementException e) {
134 | return false;
135 | }
136 | }
137 |
138 | /**
139 | * Opens the browser specified by the browserName.
140 | *
141 | * @param browser The browser to open.
142 | */
143 | @Step("Open browser: {browser}")
144 | private void openBrowser(Browser browser) {
145 | WebDriver driver;
146 | System.out.println("==========browser : " + browser);
147 | switch (browser) {
148 | case chrome:
149 | ChromeOptions co = new ChromeOptions();
150 | co.addArguments("--window-size=1920,1080");
151 | co.addArguments("--no-sandbox");
152 | co.addArguments("--headless");
153 | co.addArguments("--disable-gpu");
154 | co.addArguments("--disable-crash-reporter");
155 | co.addArguments("--disable-extensions");
156 | co.addArguments("--disable-in-process-stack-traces");
157 | co.addArguments("--disable-logging");
158 | co.addArguments("--disable-dev-shm-usage");
159 | co.addArguments("--log-level=3");
160 | co.addArguments("--output=/dev/null");
161 | co.addArguments("ignore-certificate-errors");
162 | driver = new ChromeDriver(co);
163 | break;
164 | case firefox:
165 | FirefoxOptions fo = new FirefoxOptions();
166 | fo.addArguments("--window-size=1920,1080");
167 | fo.addArguments("--no-sandbox");
168 | fo.addArguments("--headless");
169 | fo.addArguments("--disable-gpu");
170 | fo.addArguments("--disable-crash-reporter");
171 | fo.addArguments("--disable-extensions");
172 | fo.addArguments("--disable-in-process-stack-traces");
173 | fo.addArguments("--disable-logging");
174 | fo.addArguments("--disable-dev-shm-usage");
175 | fo.addArguments("--log-level=3");
176 | fo.addArguments("--output=/dev/null");
177 | fo.addArguments("ignore-certificate-errors");
178 | driver = new FirefoxDriver(fo);
179 | break;
180 | case edge:
181 | driver = new EdgeDriver();
182 | break;
183 | case ie:
184 | driver = new InternetExplorerDriver();
185 | break;
186 | case safari:
187 | driver = new SafariDriver();
188 | break;
189 | default:
190 | throw new IllegalArgumentException("Unsupported browser: " + browser);
191 | }
192 | tlDriver.set(driver);
193 | }
194 |
195 | /**
196 | * Navigates to the specified URL.
197 | *
198 | * @param url The URL to navigate to.
199 | */
200 | @Step("Navigate to URL: {url}")
201 | private void navigateTo(String url) {
202 | getDriver().navigate().to(url);
203 | }
204 |
205 | /**
206 | * Clicks on the element specified by the target.
207 | *
208 | * @param target The target element to click.
209 | */
210 | @Step("Click on element: {target}")
211 | private void click(String target) {
212 | By locator = getBy(target);
213 | getDriver().findElement(locator).click();
214 | }
215 |
216 | /**
217 | * Types the specified value into the element specified by the target.
218 | *
219 | * @param target The target element to type into.
220 | * @param value The value to type.
221 | */
222 | @Step("Type '{value}' into element: {target}")
223 | private void type(String target, String value) {
224 | By locator = getBy(target);
225 | getDriver().findElement(locator).sendKeys(value);
226 | }
227 |
228 | /**
229 | * Verifies that the text in the element specified by the target matches the
230 | * expectedText.
231 | *
232 | * @param target The target element containing the text to verify.
233 | * @param expectedText The expected text.
234 | */
235 | @Step("Verify text '{expectedText}' in element: {target}")
236 | private void verifyText(String target, String expectedText) {
237 | By locator = getBy(target);
238 | String actualText = getDriver().findElement(locator).getText();
239 | Assert.assertEquals(actualText, expectedText, "Text verification failed!");
240 | }
241 |
242 | /**
243 | * Switches to the frame specified by the frameName.
244 | *
245 | * @param frameName The name or ID of the frame to switch to.
246 | */
247 | @Step("Switch to frame: {frameName}")
248 | private void switchToFrame(String frameName) {
249 | getDriver().switchTo().frame(frameName);
250 | }
251 |
252 | /**
253 | * Switches to the default content.
254 | */
255 | @Step("Switch to default content")
256 | private void switchToDefaultContent() {
257 | getDriver().switchTo().defaultContent();
258 | }
259 |
260 | /**
261 | * Retrieves the By locator for the specified target.
262 | *
263 | * @param target The target element.
264 | * @return The By locator for the target.
265 | */
266 | private By getBy(String target) {
267 | By locator;
268 | if (target.startsWith("id=")) {
269 | locator = By.id(target.substring(3));
270 | } else if (target.startsWith("name=")) {
271 | locator = By.name(target.substring(5));
272 | } else if (target.startsWith("class=")) {
273 | locator = By.className(target.substring(6));
274 | } else if (target.startsWith("xpath=")) {
275 | locator = By.xpath(target.substring(6));
276 | } else if (target.startsWith("css=")) {
277 | locator = By.cssSelector(target.substring(4));
278 | } else if (target.startsWith("linktext=")) {
279 | locator = By.linkText(target.substring(9));
280 | } else {
281 | throw new IllegalArgumentException("Unsupported locator format: " + target);
282 | }
283 | return locator;
284 | }
285 |
286 | /**
287 | * Retrieves the WebDriver instance.
288 | *
289 | * @return The WebDriver instance.
290 | */
291 | public static WebDriver getDriver() {
292 | return tlDriver.get();
293 | }
294 |
295 | /**
296 | * Takes a screenshot of the current WebDriver instance and saves it to the
297 | * specified file.
298 | *
299 | * @param methodName The name of the method or test.
300 | * @return The path to the saved screenshot file.
301 | */
302 | public static String getScreenshot(String methodName) {
303 | File srcFile = ((TakesScreenshot) getDriver()).getScreenshotAs(OutputType.FILE);
304 | String path = System.getProperty("user.dir") + "/screenshot/" + methodName + "_" + System.currentTimeMillis()
305 | + ".png";
306 | File destination = new File(path);
307 | try {
308 | FileHandler.copy(srcFile, destination);
309 | } catch (IOException e) {
310 | e.printStackTrace();
311 | }
312 | return path;
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/listeners/ExtentReportListener.java:
--------------------------------------------------------------------------------
1 | package com.nal.listeners;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 | import java.util.Calendar;
8 | import java.util.Date;
9 |
10 | import org.testng.ITestContext;
11 | import org.testng.ITestListener;
12 | import org.testng.ITestResult;
13 |
14 | import com.aventstack.extentreports.ExtentReports;
15 | import com.aventstack.extentreports.ExtentTest;
16 | import com.aventstack.extentreports.MediaEntityBuilder;
17 | import com.aventstack.extentreports.reporter.ExtentSparkReporter;
18 | import com.nal.keywords.KeywordExecutor;
19 |
20 |
21 | public class ExtentReportListener implements ITestListener {
22 |
23 | private static final String OUTPUT_FOLDER = "./reports/";
24 | private static final String FILE_NAME = "TestExecutionReport.html";
25 |
26 | private static ExtentReports extent = init();
27 | public static ThreadLocal test = new ThreadLocal();
28 | private static ExtentReports extentReports;
29 |
30 |
31 | private static ExtentReports init() {
32 |
33 | Path path = Paths.get(OUTPUT_FOLDER);
34 | // if directory exists?
35 | if (!Files.exists(path)) {
36 | try {
37 | Files.createDirectories(path);
38 | } catch (IOException e) {
39 | // fail to create directory
40 | e.printStackTrace();
41 | }
42 | }
43 |
44 | extentReports = new ExtentReports();
45 | ExtentSparkReporter reporter = new ExtentSparkReporter(OUTPUT_FOLDER + FILE_NAME);
46 | reporter.config().setReportName("Open Cart Automation Test Results");
47 | extentReports.attachReporter(reporter);
48 | extentReports.setSystemInfo("System", "MAC");
49 | extentReports.setSystemInfo("Author", "Naveen AutomationLabs");
50 | extentReports.setSystemInfo("Build#", "1.1");
51 | extentReports.setSystemInfo("Team", "OpenCart QA Team");
52 | extentReports.setSystemInfo("Customer Name", "NAL");
53 | extentReports.setSystemInfo("ENV NAME", System.getProperty("env"));
54 |
55 | return extentReports;
56 | }
57 |
58 | @Override
59 | public synchronized void onStart(ITestContext context) {
60 | System.out.println("Test Suite started!");
61 |
62 | }
63 |
64 | @Override
65 | public synchronized void onFinish(ITestContext context) {
66 | System.out.println(("Test Suite is ending!"));
67 | extent.flush();
68 | test.remove();
69 | }
70 |
71 | @Override
72 | public synchronized void onTestStart(ITestResult result) {
73 | String methodName = result.getMethod().getMethodName();
74 | String qualifiedName = result.getMethod().getQualifiedName();
75 | int last = qualifiedName.lastIndexOf(".");
76 | int mid = qualifiedName.substring(0, last).lastIndexOf(".");
77 | String className = qualifiedName.substring(mid + 1, last);
78 |
79 | System.out.println(methodName + " started!");
80 | ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName(),
81 | result.getMethod().getDescription());
82 |
83 | extentTest.assignCategory(result.getTestContext().getSuite().getName());
84 | /*
85 | * methodName = StringUtils.capitalize(StringUtils.join(StringUtils.
86 | * splitByCharacterTypeCamelCase(methodName), StringUtils.SPACE));
87 | */
88 | extentTest.assignCategory(className);
89 | test.set(extentTest);
90 | test.get().getModel().setStartTime(getTime(result.getStartMillis()));
91 | }
92 |
93 | public synchronized void onTestSuccess(ITestResult result) {
94 | String methodName = result.getMethod().getMethodName();
95 | System.out.println((methodName + " passed!"));
96 | test.get().pass("Test passed");
97 | //test.get().pass(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromPath(DriverFactory.getScreenshot(methodName), methodName).build());
98 | test.get().getModel().setEndTime(getTime(result.getEndMillis()));
99 | }
100 |
101 | public synchronized void onTestFailure(ITestResult result) {
102 | System.out.println((result.getMethod().getMethodName() + " failed!"));
103 | String methodName = result.getMethod().getMethodName();
104 | test.get().fail("Test failed");
105 | test.get().fail(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromPath(KeywordExecutor.getScreenshot(methodName), methodName).build());
106 | test.get().getModel().setEndTime(getTime(result.getEndMillis()));
107 | }
108 |
109 | public synchronized void onTestSkipped(ITestResult result) {
110 | System.out.println((result.getMethod().getMethodName() + " skipped!"));
111 | //String methodName = result.getMethod().getMethodName();
112 |
113 | test.get().skip("Test skipped");
114 |
115 | //test.get().skip(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromPath(DriverFactory.getScreenshot(methodName), methodName).build());
116 | test.get().getModel().setEndTime(getTime(result.getEndMillis()));
117 | }
118 |
119 | public synchronized void onTestFailedButWithinSuccessPercentage(ITestResult result) {
120 | System.out.println(("onTestFailedButWithinSuccessPercentage for " + result.getMethod().getMethodName()));
121 | }
122 |
123 | private Date getTime(long millis) {
124 | Calendar calendar = Calendar.getInstance();
125 | calendar.setTimeInMillis(millis);
126 | return calendar.getTime();
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/listeners/FrameworkListener.java:
--------------------------------------------------------------------------------
1 | package com.nal.listeners;
2 |
3 | import org.testng.ITestContext;
4 | import org.testng.ITestListener;
5 | import org.testng.ITestResult;
6 |
7 | //custom listener
8 | public class FrameworkListener implements ITestListener{
9 |
10 |
11 | @Override
12 | public synchronized void onStart(ITestContext context) {
13 | System.out.println("Test Suite started!");
14 |
15 | }
16 |
17 | @Override
18 | public synchronized void onFinish(ITestContext context) {
19 | System.out.println(("Test Suite is ending!"));
20 |
21 | }
22 |
23 | @Override
24 | public synchronized void onTestStart(ITestResult result) {
25 | String methodName = result.getMethod().getMethodName();
26 | String qualifiedName = result.getMethod().getQualifiedName();
27 | int last = qualifiedName.lastIndexOf(".");
28 | int mid = qualifiedName.substring(0, last).lastIndexOf(".");
29 | String className = qualifiedName.substring(mid + 1, last);
30 |
31 | System.out.println("test method started : " + className + " : " + methodName);
32 |
33 | }
34 |
35 | public synchronized void onTestSuccess(ITestResult result) {
36 | String methodName = result.getMethod().getMethodName();
37 | System.out.println((methodName + " passed!"));
38 |
39 | }
40 |
41 | public synchronized void onTestFailure(ITestResult result) {
42 | String methodName = result.getMethod().getMethodName();
43 | System.out.println(methodName + " failed!");
44 |
45 | }
46 |
47 | public synchronized void onTestSkipped(ITestResult result) {
48 | String methodName = result.getMethod().getMethodName();
49 | System.out.println(methodName + " skipped!");
50 | }
51 |
52 |
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/listeners/TestAllureListener.java:
--------------------------------------------------------------------------------
1 | package com.nal.listeners;
2 |
3 |
4 | import java.io.IOException;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.nio.file.Paths;
8 |
9 | import org.openqa.selenium.OutputType;
10 | import org.openqa.selenium.TakesScreenshot;
11 | import org.openqa.selenium.WebDriver;
12 | import org.testng.ITestContext;
13 | import org.testng.ITestListener;
14 | import org.testng.ITestResult;
15 |
16 | import com.nal.keywords.KeywordExecutor;
17 |
18 | import io.qameta.allure.Attachment;
19 |
20 |
21 | public class TestAllureListener implements ITestListener {
22 |
23 |
24 |
25 | private static String getTestMethodName(ITestResult iTestResult) {
26 | return iTestResult.getMethod().getConstructorOrMethod().getName();
27 | }
28 |
29 |
30 | // Text attachments for Allure
31 | @Attachment(value = "Page screenshot", type = "image/png")
32 | public byte[] saveScreenshotPNG(WebDriver driver) {
33 | return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
34 | }
35 |
36 | // Text attachments for Allure
37 | @Attachment(value = "{0}", type = "text/plain")
38 | public static String saveTextLog(String message) {
39 | return message;
40 | }
41 |
42 | // HTML attachments for Allure
43 | @Attachment(value = "{0}", type = "text/html")
44 | public static String attachHtml(String html) {
45 | return html;
46 | }
47 |
48 | // Attaching CSV file content as text/plain attachment
49 | // Attaching CSV file as a text/csv attachment
50 | @Attachment(value = "CSV File", type = "text/csv")
51 | public byte[] attachCSVFile(String filePath) {
52 | try {
53 | Path path = Paths.get(filePath);
54 | return Files.readAllBytes(path);
55 | } catch (IOException e) {
56 | e.printStackTrace();
57 | return null;
58 | }
59 | }
60 |
61 | @Override
62 | public void onStart(ITestContext iTestContext) {
63 | System.out.println("I am in onStart method " + iTestContext.getName());
64 | }
65 |
66 | @Override
67 | public void onFinish(ITestContext iTestContext) {
68 | System.out.println("I am in onFinish method " + iTestContext.getName());
69 | //attachCSVFile(TestExecutor.csvPath);
70 |
71 | }
72 |
73 | @Override
74 | public void onTestStart(ITestResult iTestResult) {
75 | System.out.println("I am in onTestStart method " + getTestMethodName(iTestResult) + " start");
76 | }
77 |
78 | @Override
79 | public void onTestSuccess(ITestResult iTestResult) {
80 | System.out.println("I am in onTestSuccess method " + getTestMethodName(iTestResult) + " succeed");
81 | }
82 |
83 | @Override
84 | public void onTestFailure(ITestResult iTestResult) {
85 | System.out.println("I am in onTestFailure method " + getTestMethodName(iTestResult) + " failed");
86 | //Object testClass = iTestResult.getInstance();
87 | //WebDriver driver = BasePage.getDriver();
88 | // Allure ScreenShotRobot and SaveTestLog
89 | if (KeywordExecutor.getDriver() instanceof WebDriver) {
90 | System.out.println("Screenshot captured for test case:" + getTestMethodName(iTestResult));
91 | saveScreenshotPNG(KeywordExecutor.getDriver());
92 | }
93 | // Save a log on allure.
94 | saveTextLog(getTestMethodName(iTestResult) + " failed and screenshot taken!");
95 | }
96 |
97 | @Override
98 | public void onTestSkipped(ITestResult iTestResult) {
99 | System.out.println("I am in onTestSkipped method " + getTestMethodName(iTestResult) + " skipped");
100 | }
101 |
102 | @Override
103 | public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) {
104 | System.out.println("Test failed but it is in defined success ratio " + getTestMethodName(iTestResult));
105 | }
106 |
107 | }
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/main/java/com/nal/utils/CSVReader.java:
--------------------------------------------------------------------------------
1 | package com.nal.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.FileReader;
5 | import java.io.IOException;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import com.nal.keywords.KeywordExecutor;
10 |
11 | /**
12 | * @author naveenautomationlabs
13 | * This class reads test cases from CSV files and executes them using a KeywordExecutor.
14 | */
15 | public class CSVReader {
16 |
17 | private static final Object lock = new Object();
18 |
19 | /**
20 | * Path to the CSV file being processed.
21 | */
22 | public static String csvPath = null;
23 |
24 | /**
25 | * Reads and executes test cases from a CSV file.
26 | *
27 | * @param csvFile The path to the CSV file containing test cases.
28 | */
29 | public void executeTestCasesFromCSV(String csvFile) {
30 | csvPath = "./src/test/resources/csvs/" + csvFile;
31 | printTestCasesFromCSV(csvFile);
32 | try (BufferedReader br = new BufferedReader(
33 | new FileReader("./src/test/resources/csvs/" + csvFile))) {
34 | String line;
35 | String currentTestCase = null;
36 | List testSteps = new ArrayList<>();
37 |
38 | while ((line = br.readLine()) != null) {
39 | String[] data = line.split(",");
40 | String testCaseName = data[0];
41 | String keyword = data[1].trim();
42 | String target = data[2].trim();
43 | String value = (data.length == 4) ? data[3].trim() : "";
44 |
45 | if (!testCaseName.equals(currentTestCase)) {
46 | // Execute previous test case steps
47 | if (currentTestCase != null) {
48 | KeywordExecutor keywordExecutor = new KeywordExecutor();
49 | keywordExecutor.executeTestSteps(currentTestCase, testSteps);
50 | testSteps.clear();
51 | }
52 | currentTestCase = testCaseName;
53 | }
54 |
55 | // Add current test step to the list
56 | testSteps.add(keyword + "," + target + "," + value);
57 | }
58 |
59 | // Execute the last test case
60 | if (currentTestCase != null) {
61 | KeywordExecutor keywordExecutor = new KeywordExecutor();
62 | keywordExecutor.executeTestSteps(currentTestCase, testSteps);
63 | }
64 | } catch (IOException e) {
65 | e.printStackTrace();
66 | }
67 | }
68 |
69 | /**
70 | * Prints the test cases from the given CSV file.
71 | *
72 | * @param csvFile The path to the CSV file containing test cases.
73 | */
74 | private void printTestCasesFromCSV(String csvFile) {
75 | synchronized (lock) {
76 | try (BufferedReader br = new BufferedReader(
77 | new FileReader("./src/test/resources/csvs/" + csvFile))) {
78 | String line;
79 | System.out.println("Test cases from CSV file: " + csvFile);
80 | System.out.println(
81 | "+-------------------------------------------------------------------------------------------+");
82 | System.out.printf("| %-15s | %-15s | %-50s | %-20s |\n", "Test Case", "Keyword", "Target", "Value");
83 | System.out.println(
84 | "+-------------------------------------------------------------------------------------------+");
85 | while ((line = br.readLine()) != null) {
86 | String[] data = line.split(",");
87 | String testCase = data[0];
88 | String keyword = data[1];
89 | String target = data[2];
90 | String value = "";
91 | if (data.length > 3) {
92 | value = data[3];
93 | }
94 | System.out.printf("| %-15s | %-15s | %-50s | %-20s |\n", testCase, keyword, target, value);
95 | }
96 | System.out.println("+----------------------------------------------------------------+");
97 | System.out.println("Total test cases: " + getTestCaseCount(csvFile));
98 | System.out.println("+----------------------------------------------------------------+");
99 | System.out.println();
100 | System.out.println();
101 | } catch (IOException e) {
102 | e.printStackTrace();
103 | }
104 | }
105 | }
106 |
107 | /**
108 | * Counts the number of test cases in the given CSV file.
109 | *
110 | * @param csvFile The path to the CSV file containing test cases.
111 | * @return The number of test cases in the CSV file.
112 | * @throws IOException If an I/O error occurs.
113 | */
114 | private int getTestCaseCount(String csvFile) throws IOException {
115 | int count = 0;
116 | try (BufferedReader br = new BufferedReader(
117 | new FileReader("./src/test/resources/csvs/" + csvFile))) {
118 | while (br.readLine() != null) {
119 | count++;
120 | }
121 | }
122 | return count;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/test/java/tests/KeywordDrivenTest.java:
--------------------------------------------------------------------------------
1 |
2 | package tests;
3 |
4 | import org.testng.annotations.AfterMethod;
5 | import org.testng.annotations.Listeners;
6 | import org.testng.annotations.Test;
7 |
8 | import com.nal.keywords.KeywordExecutor;
9 | import com.nal.listeners.TestAllureListener;
10 |
11 | @Listeners(TestAllureListener.class)
12 | public class KeywordDrivenTest {
13 |
14 | @AfterMethod
15 | public void tearDown() {
16 | if (KeywordExecutor.getDriver() != null) {
17 | KeywordExecutor.getDriver().close();
18 | }
19 | }
20 |
21 | @Test
22 | public void executeLoginTest() {
23 | KeywordExecutor keywordExecutor = new KeywordExecutor();
24 | keywordExecutor.executeTestCasesFromCSV("login_test.csv");
25 | }
26 |
27 | @Test
28 | public void executeSearchTest() {
29 | KeywordExecutor keywordExecutor = new KeywordExecutor();
30 | keywordExecutor.executeTestCasesFromCSV("search_test.csv");
31 | }
32 |
33 | @Test
34 | public void executeHomeTest() {
35 | KeywordExecutor keywordExecutor = new KeywordExecutor();
36 | keywordExecutor.executeTestCasesFromCSV("home_test.csv");
37 | }
38 | }
--------------------------------------------------------------------------------
/src/test/resources/csvs/home_test.csv:
--------------------------------------------------------------------------------
1 | Home, OpenBrowser, chrome,
2 | Home, NavigateTo, https://naveenautomationlabs.com/opencart/index.php?route=account/account,
3 | Home, Type, id=input-email, pwtest@opencart.com
4 | Home, Type, id=input-password, pw123
5 | Home, Click, xpath=//input[@value='Login'],
6 | Home, VerifyText, xpath=//h2[normalize-space()='My Account'], My Account
--------------------------------------------------------------------------------
/src/test/resources/csvs/login_test.csv:
--------------------------------------------------------------------------------
1 | Login, OpenBrowser, chrome,
2 | Login, NavigateTo, https://naveenautomationlabs.com/opencart/index.php?route=account/account,
3 | Login, Type, id=input-email, pwtest@opencart.com
4 | Login, Type, id=input-password, pw123
5 | Login, Click, xpath=//input[@value='Login'],
6 | Login, VerifyText, xpath=//h2[normalize-space()='My Account'], My Account
--------------------------------------------------------------------------------
/src/test/resources/csvs/search_test.csv:
--------------------------------------------------------------------------------
1 | Search, OpenBrowser, firefox,
2 | Search, NavigateTo, https://naveenautomationlabs.com/opencart/index.php?route=account/account,
3 | Search, Type, id=input-email, pwtest@opencart.com
4 | Search, Type, id=input-password, pw123
5 | Search, Click, xpath=//input[@value='Login'],
6 | Search,Type,name=search,macbook
7 | Search,Click,css=button[class='btn btn-default btn-lg'],
--------------------------------------------------------------------------------
/src/test/resources/testrunner/testng.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------