├── .gitignore ├── README.md ├── TestNG.xml ├── pom.xml └── src ├── main └── java │ ├── page │ ├── BasePage.java │ ├── HomePage.java │ ├── LoginPage.java │ └── SearchResultPage.java │ └── util │ ├── AllureReportListener.java │ ├── PropertyFileReader.java │ └── driver │ ├── DriverFactory.java │ └── DriverHolder.java └── test ├── java └── test │ ├── BaseTest.java │ ├── LoginTest.java │ └── SearchTest.java └── resources └── config.properties /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /target 3 | /test-output 4 | /allure-results 5 | /selenium-testng-allure-report-demo.iml 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Selenium TestNG Project with Allure Reporting 2 | 3 | This is a demo project for Selenium Page Object Model with Allure reporting. 4 | 5 | ### Pre-requisites 6 | * Java 7 | * Maven 8 | * [Allure](https://docs.qameta.io/allure/#_installing_a_commandline) 9 | * IntelliJ IDEA 10 | 11 | ### Steps 12 | 1. Clone this project 13 | 2. Open the project in Intellij IDEA 14 | 3. Run TestNG.XML 15 | 4. Open the terminal in Intellij IDEA 16 | 5. Execute **`allure serve allure-results`** 17 | -------------------------------------------------------------------------------- /TestNG.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.selenium.demo 8 | selenium-testng-allure-report-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.8.13 13 | UTF-8 14 | 15 | 16 | 17 | 18 | org.seleniumhq.selenium 19 | selenium-java 20 | 3.141.59 21 | 22 | 23 | io.github.bonigarcia 24 | webdrivermanager 25 | 3.6.1 26 | 27 | 28 | org.testng 29 | testng 30 | 6.14.3 31 | 32 | 33 | io.qameta.allure 34 | allure-testng 35 | 2.12.0 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-compiler-plugin 44 | 45 | 1.8 46 | 1.8 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-surefire-plugin 52 | 2.20 53 | 54 | 55 | TestNG.xml 56 | 57 | 58 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" 59 | 60 | 61 | 62 | 63 | org.aspectj 64 | aspectjweaver 65 | ${aspectj.version} 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/java/page/BasePage.java: -------------------------------------------------------------------------------- 1 | package page; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.ui.ExpectedConditions; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | import java.util.List; 10 | 11 | public class BasePage { 12 | 13 | public static WebDriver driver; 14 | 15 | public BasePage(WebDriver driver) { 16 | BasePage.driver = driver; 17 | } 18 | 19 | public void waitUntilElementVisible(By by) { 20 | WebDriverWait wait = new WebDriverWait(driver, 60); 21 | wait.until(ExpectedConditions.visibilityOfElementLocated(by)); 22 | } 23 | 24 | public void waitUntilElementClickable(By by) { 25 | WebDriverWait wait = new WebDriverWait(driver, 60); 26 | wait.until(ExpectedConditions.elementToBeClickable(by)); 27 | } 28 | 29 | public void click(By by) { 30 | waitUntilElementClickable(by); 31 | driver.findElement(by).click(); 32 | } 33 | 34 | public WebElement getElement(By by) { 35 | waitUntilElementVisible(by); 36 | return driver.findElement(by); 37 | } 38 | 39 | public List getElements(By by) { 40 | waitUntilElementVisible(by); 41 | return driver.findElements(by); 42 | } 43 | 44 | public void sendKeys(By by, String text) { 45 | waitUntilElementVisible(by); 46 | driver.findElement(by).sendKeys(text); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/page/HomePage.java: -------------------------------------------------------------------------------- 1 | package page; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | 6 | public class HomePage extends BasePage { 7 | 8 | private final By usernameLabel = By.xpath("//div[@class='header_user_info']//span"); 9 | private final By searchTextBox = By.id("search_query_top"); 10 | private final By searchButton = By.cssSelector("button[name='submit_search']"); 11 | 12 | public HomePage(WebDriver driver) { 13 | super(driver); 14 | } 15 | 16 | public String getLoggedInUsername() { 17 | return getElement(usernameLabel).getText(); 18 | } 19 | 20 | public void enterSearchItem(String itemName) { 21 | sendKeys(searchTextBox, itemName); 22 | } 23 | 24 | public void enterSearchButton() { 25 | click(searchButton); 26 | } 27 | 28 | public void searchItem(String itemName) { 29 | enterSearchItem(itemName); 30 | enterSearchButton(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/page/LoginPage.java: -------------------------------------------------------------------------------- 1 | package page; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | 6 | public class LoginPage extends BasePage { 7 | 8 | private final By emailTextBox = By.id("email"); 9 | private final By passwordTextBox = By.id("passwd"); 10 | private final By signInButton = By.id("SubmitLogin"); 11 | 12 | public LoginPage(WebDriver driver) { 13 | super(driver); 14 | } 15 | 16 | public void setEmail(String email) { 17 | sendKeys(emailTextBox, email); 18 | } 19 | 20 | public void setPassword(String password) { 21 | sendKeys(passwordTextBox, password); 22 | } 23 | 24 | public void clickSignIn() { 25 | click(signInButton); 26 | } 27 | 28 | public void login(String email, String password) { 29 | setEmail(email); 30 | setPassword(password); 31 | clickSignIn(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/page/SearchResultPage.java: -------------------------------------------------------------------------------- 1 | package page; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | 6 | public class SearchResultPage extends BasePage{ 7 | 8 | private final By searchResultsList = By.xpath("//div[@class='left-block']//div[@class='product-image-container']"); 9 | private final By firstSearchResultName = By.xpath("//div[@class='right-block']//h5//a"); 10 | private final By firstSearchResultPrice = By.xpath("//div[@class='right-block']//span[@itemprop='price']"); 11 | 12 | public SearchResultPage(WebDriver driver) { 13 | super(driver); 14 | } 15 | 16 | public int getSearchResultCount() { 17 | return getElements(searchResultsList).size(); 18 | } 19 | 20 | public String getFirstSearchResultName() { 21 | return getElement(firstSearchResultName).getText(); 22 | } 23 | 24 | public String getFirstSearchResultPrice() { 25 | return getElement(firstSearchResultPrice).getText(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/util/AllureReportListener.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import io.qameta.allure.Attachment; 4 | import org.openqa.selenium.OutputType; 5 | import org.openqa.selenium.TakesScreenshot; 6 | import org.openqa.selenium.WebDriver; 7 | import org.testng.ITestContext; 8 | import org.testng.ITestListener; 9 | import org.testng.ITestResult; 10 | 11 | import static util.driver.DriverHolder.getDriver; 12 | 13 | public class AllureReportListener implements ITestListener { 14 | 15 | @Attachment(value = "Page screenshot", type = "image/png") 16 | public byte[] saveScreenshotPNG (WebDriver driver) { 17 | return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES); 18 | } 19 | 20 | @Override 21 | public void onStart(ITestContext iTestContext) { 22 | System.out.println("Starting Test Suite '" + iTestContext.getName() + "'......."); 23 | iTestContext.setAttribute("WebDriver", getDriver()); 24 | } 25 | 26 | @Override 27 | public void onFinish(ITestContext iTestContext) { 28 | System.out.println("Finished Test Suite '" + iTestContext.getName() + "'"); 29 | } 30 | 31 | @Override 32 | public void onTestStart(ITestResult iTestResult) { 33 | System.out.println("Starting Test Method '" + getTestMethodName(iTestResult) + "'"); 34 | } 35 | 36 | @Override 37 | public void onTestSuccess(ITestResult iTestResult) { 38 | System.out.println("Test Method '" + getTestMethodName(iTestResult) + "' is Passed"); 39 | } 40 | 41 | @Override 42 | public void onTestFailure(ITestResult iTestResult) { 43 | System.out.println("Test Method '" + getTestMethodName(iTestResult) + "' is Failed"); 44 | if (getDriver() != null) { 45 | System.out.println("Screenshot has captured for the Test Method '" + getTestMethodName(iTestResult) + "'"); 46 | saveScreenshotPNG(getDriver()); 47 | } 48 | } 49 | 50 | @Override 51 | public void onTestSkipped(ITestResult iTestResult) { 52 | System.out.println("Test Method '" + getTestMethodName(iTestResult) + "' is Skipped"); 53 | } 54 | 55 | @Override 56 | public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) { 57 | } 58 | 59 | private static String getTestMethodName(ITestResult iTestResult) { 60 | return iTestResult.getMethod().getConstructorOrMethod().getName(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/util/PropertyFileReader.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.Properties; 7 | 8 | public class PropertyFileReader { 9 | 10 | public static String getProperty(String propertyName) { 11 | String propertyValue = null; 12 | 13 | try (InputStream input = new FileInputStream("./src/test/resources/config.properties")) { 14 | Properties prop = new Properties(); 15 | prop.load(input); 16 | propertyValue = prop.getProperty(propertyName); 17 | } catch (IOException ex) { 18 | ex.printStackTrace(); 19 | } 20 | return propertyValue; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/util/driver/DriverFactory.java: -------------------------------------------------------------------------------- 1 | package util.driver; 2 | 3 | import io.github.bonigarcia.wdm.WebDriverManager; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.chrome.ChromeDriver; 6 | import org.openqa.selenium.chrome.ChromeOptions; 7 | import org.openqa.selenium.edge.EdgeDriver; 8 | import org.openqa.selenium.firefox.FirefoxBinary; 9 | import org.openqa.selenium.firefox.FirefoxDriver; 10 | import org.openqa.selenium.firefox.FirefoxOptions; 11 | 12 | public class DriverFactory { 13 | 14 | public static WebDriver getNewDriverInstance(String browserName) { 15 | switch (browserName.toLowerCase()) { 16 | case "chrome-headless": 17 | ChromeOptions chromeOptions = new ChromeOptions(); 18 | chromeOptions.addArguments("--headless"); 19 | chromeOptions.addArguments("start-maximized"); 20 | WebDriverManager.chromedriver().setup(); 21 | return new ChromeDriver(chromeOptions); 22 | case "firefox": 23 | WebDriverManager.firefoxdriver().setup(); 24 | return new FirefoxDriver(); 25 | case "firefox-headless": 26 | FirefoxBinary firefoxBinary = new FirefoxBinary(); 27 | firefoxBinary.addCommandLineOptions("--headless"); 28 | firefoxBinary.addCommandLineOptions("--window-size=1280x720"); 29 | FirefoxOptions firefoxOptions = new FirefoxOptions(); 30 | firefoxOptions.setBinary(firefoxBinary); 31 | WebDriverManager.firefoxdriver().setup(); 32 | return new FirefoxDriver(firefoxOptions); 33 | case "edge": 34 | WebDriverManager.edgedriver().setup(); 35 | return new EdgeDriver(); 36 | default: 37 | WebDriverManager.chromedriver().setup(); 38 | return new ChromeDriver(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/util/driver/DriverHolder.java: -------------------------------------------------------------------------------- 1 | package util.driver; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | 5 | public class DriverHolder { 6 | 7 | private static final ThreadLocal driver = new ThreadLocal<>(); 8 | 9 | public static WebDriver getDriver() { 10 | return driver.get(); 11 | } 12 | 13 | public static void setDriver(WebDriver driver) { 14 | DriverHolder.driver.set(driver); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/test/BaseTest.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import org.testng.annotations.AfterMethod; 4 | import org.testng.annotations.BeforeMethod; 5 | import util.driver.DriverFactory; 6 | 7 | import static util.PropertyFileReader.getProperty; 8 | import static util.driver.DriverHolder.getDriver; 9 | import static util.driver.DriverHolder.setDriver; 10 | 11 | public class BaseTest { 12 | 13 | @BeforeMethod 14 | public void before() { 15 | setDriver(DriverFactory.getNewDriverInstance(getProperty("browser"))); 16 | getDriver().manage().window().maximize(); 17 | getDriver().get(getProperty("application_url")); 18 | } 19 | 20 | @AfterMethod 21 | public void after() { 22 | if (getDriver() != null) { 23 | getDriver().quit(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/test/LoginTest.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import io.qameta.allure.*; 4 | import org.testng.annotations.BeforeMethod; 5 | import org.testng.annotations.Test; 6 | import page.HomePage; 7 | import page.LoginPage; 8 | 9 | import static io.qameta.allure.SeverityLevel.BLOCKER; 10 | import static io.qameta.allure.SeverityLevel.CRITICAL; 11 | import static org.testng.Assert.assertEquals; 12 | import static util.driver.DriverHolder.getDriver; 13 | 14 | @Epic("User Management") 15 | @Feature("Login") 16 | public class LoginTest extends BaseTest { 17 | 18 | private LoginPage loginPage; 19 | 20 | @BeforeMethod 21 | public void loginBeforeMethod() { 22 | loginPage = new LoginPage(getDriver()); 23 | } 24 | 25 | @Test(description = "Verify that a valid user can login to the application") 26 | @Severity(BLOCKER) 27 | @Description("Verify that a valid user can login to the application") 28 | @Story("As a user I should be able to login to the application") 29 | public void testValidLogin() { 30 | loginPage.login("osanda@mailinator.com","1qaz2wsx@"); 31 | assertEquals(new HomePage(getDriver()).getLoggedInUsername(), "Osanda Nimalarathna"); 32 | } 33 | 34 | @Test(description = "Verify that an invalid user cannot login to the application") 35 | @Severity(CRITICAL) 36 | @Description("Verify that an invalid user cannot login to the application") 37 | @Story("As a user I should be able to login to the application") 38 | public void testInvalidLogin() { 39 | loginPage.login("osanda@mailinator.com","abc12"); 40 | assertEquals(getDriver().getTitle(), "Login - My Store"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/test/SearchTest.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import io.qameta.allure.*; 4 | import org.testng.annotations.BeforeMethod; 5 | import org.testng.annotations.Test; 6 | import page.HomePage; 7 | import page.LoginPage; 8 | import page.SearchResultPage; 9 | 10 | import static io.qameta.allure.SeverityLevel.CRITICAL; 11 | import static org.testng.Assert.assertEquals; 12 | import static org.testng.Assert.assertTrue; 13 | import static util.driver.DriverHolder.getDriver; 14 | 15 | @Epic("Order Placing") 16 | @Feature("Search") 17 | public class SearchTest extends BaseTest { 18 | 19 | private SearchResultPage searchResultPage; 20 | 21 | @BeforeMethod 22 | public void searchBeforeMethod() { 23 | new LoginPage(getDriver()).login("osanda@mailinator.com","1qaz2wsx@"); 24 | searchResultPage = new SearchResultPage(getDriver()); 25 | new HomePage(getDriver()).searchItem("T-shirt"); 26 | } 27 | 28 | @Test(description = "Verify that the search results are not empty for the keyword 'T-shirt'") 29 | @Severity(CRITICAL) 30 | @Description("Verify that the search results are not empty for the keyword 'T-shirt'") 31 | @Story("As a user I should be able to search items") 32 | public void testSearchResultCount() { 33 | int actualSearchResultCount = searchResultPage.getSearchResultCount(); 34 | assertTrue(actualSearchResultCount > 0); 35 | assertEquals(actualSearchResultCount,1); 36 | } 37 | 38 | @Test(description = "Verify the search result name and price for the keyword 'T-shirt'") 39 | @Severity(CRITICAL) 40 | @Description("Verify the search result name and price for the keyword 'T-shirt'") 41 | @Story("As a user I should be able to search items") 42 | public void testSearchResult() { 43 | assertTrue(searchResultPage.getFirstSearchResultName().contains("Faded Short Sleeve T-shirts")); 44 | assertEquals(searchResultPage.getFirstSearchResultPrice(), "$16.51"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/resources/config.properties: -------------------------------------------------------------------------------- 1 | # Test Configs 2 | application_url=http://automationpractice.com/index.php?controller=authentication&back=my-account 3 | browser=Chrome --------------------------------------------------------------------------------