diff --git a/.classpath b/.classpath new file mode 100644 index 00000000..db3ceb26 --- /dev/null +++ b/.classpath @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 0275ff56..98a6bc15 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build .idea -.gradle \ No newline at end of file +.gradle +/target/ diff --git a/.project b/.project new file mode 100644 index 00000000..193ba108 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + codingRound + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..44322481 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,13 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 00000000..14b697b7 --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/REVIEW_COMMENTS_&_KEY_POINTS.txt b/REVIEW_COMMENTS_&_KEY_POINTS.txt new file mode 100644 index 00000000..59c51460 --- /dev/null +++ b/REVIEW_COMMENTS_&_KEY_POINTS.txt @@ -0,0 +1,109 @@ +Review Points And Comments: + +Review Comments and Key points on the fixes and framework created are Oredered as follows: + + +(1) Common and Test Class Level Review on design and errors. +(2) Framework design pattern, files placing, reusability, reporting. + + + 1. Test Class Level Review on design and errors. + +(i) Common Issues: + + (a). set the path for driver before initialize the same. + + (b). create a common utility to launch driver and set chrome driver path. + + (c). create property file to input test configuration values i.e browser name, driver path other common configuration needs before test. + + (d). it is better to have test case executed via testNG xml while using testNG, hence it should be configured right. + + (e). Should try to keep the implementation for tests abstract/ hidden and reusable and add provision for further updates of the same + which would assure maintainability. + + (f). Assert every validation and report with screenshot for failed step/every step if possible. Since, html results + can be easily edited and hence for show casing tests to client is one step ahead if the tests have proper + evidences. + + (g). Must avoid using thread.sleep (hard wait of any type). Instead use explicit waits. + + (h). should follow a proper design pattern across the tests for efficient testing i.e page factory for example. + + (i). Always the tests must NOT be placed/developed in the main src folder, it should be placed in the test src folder + the main should only have common utils. + + (j) The classes should not be developed in "default package" it should be developed in a properly created + package with correct naming conventions. + + (k) The drivers can be placed in a separate relevant folder which can make the framework presentable. + + (l) Important of all a framework or automation is about reusabilty which requires reusable library for all + the tests. + + +(ii)FlightBookingTest: + + (a).Use explicit waits. + + (b).Update the chrome driver to latest for supporting latest chrome versions. It can cause errors during execution. + such that the chrome driver which was already there caused exception when sending text to 'from' text box + which got fixed after updating the chrome driver. + + (c).Xpath Id for the To(destination) text box was not correct i.e the actual value for the attribute id is 'ToTag' + but in script the vale was'toTag' hence it throws 'NoSuchElementException. + + (d).The date picker xpath is hard coded to pick a date and not flexible which is not good for a locator. Should change the + xpath in such a way that it can take any date from the user. write a common method. + + (e).Assesrtion should be done specifically whether Bangalore to New Delhi flights are shown and not just 'searchSummary' text + so that what gets Asserted will completley validate the scenario. + + +(ii)HotelBookingtest: + + (a). This class has pagefactory pattern implemented for finding elements which was missing "PageFactory.initElements()" this method + will implicitly call the findElement method from behind without which the script fails. + + (b). Date picker must be automated for any inputs from the user and should be reusable. + + +(iii)SignInTest: + + (a). Identify whether an element is within a frame i.e "SignIn" button is an element located within a frame + because of which the element cannot be identified unless switched to that frame. + + + +Key Points of the framework developed and fixed + + 2 Framework design pattern, files placing, reusability, reporting. + + (a). An automation framework must follow a design pattern with correct usage of OOP's concepts + for better understanding, readability and reusability. + + The fixes made to the task does not only resolve the issues but also follows a strong "Page Abstraction/Page Factory Pattern" + with "LoadableComponent" implemented for every page i.e "FlightBookingPage.class", "HotelBookingPage.class", + "SearchSummaryPage.class", "SignInPage.class". + + + (b). Common Reusable Library "UiCommons" is used which was not present. + + (c). "DriverFactory"class is implemented for initializing driver and closing the same which can be used across + tests. + + (d). Input/output utilities created to read test configuration properties from ".properties" file. + + (e). Listener class implemented for running failed tests again, the number of times as user specified. + + (f). Listener class implemented for intuitive reporting with html that has screenshots attached within the html report page. + + (g). TestNG xml included for running as TestNG suite. + + (h). Proper assertion done for validation. + + +**Run the tests using TestNg.xml present as suite to generate reports and retry failed. +**The results will be generated in "ExtentReports" folder within the project, to view the same please,refresh the project + + diff --git a/chromedriver_linux b/drivers/chromedriver_linux old mode 100755 new mode 100644 similarity index 100% rename from chromedriver_linux rename to drivers/chromedriver_linux diff --git a/chromedriver b/drivers/chromedriver_mac old mode 100755 new mode 100644 similarity index 100% rename from chromedriver rename to drivers/chromedriver_mac diff --git a/chromedriver.exe b/drivers/chromedriver_win.exe old mode 100755 new mode 100644 similarity index 52% rename from chromedriver.exe rename to drivers/chromedriver_win.exe index 4bfff1ef..d7ac3c69 Binary files a/chromedriver.exe and b/drivers/chromedriver_win.exe differ diff --git a/pom.xml b/pom.xml index 839ed21f..cf0bcc28 100644 --- a/pom.xml +++ b/pom.xml @@ -1,28 +1,40 @@ - - 4.0.0 - com.testvagrant.codingRound - codoingRound - 1.0-SNAPSHOT - - - junit - junit - 4.11 - compile - - - org.seleniumhq.selenium - selenium-java - 3.6.0 - compile - - - org.testng - testng - 6.11 - compile - - + + 4.0.0 + com.testvagrant.codingRound + codoingRound + 1.0-SNAPSHOT + + + junit + junit + 4.11 + compile + + + org.seleniumhq.selenium + selenium-java + 3.6.0 + compile + + + org.testng + testng + 6.11 + compile + + + commons-io + commons-io + 2.6 + + + com.relevantcodes + extentreports + 2.41.2 + + diff --git a/src/main/java/FlightBookingTest.java b/src/main/java/FlightBookingTest.java deleted file mode 100644 index 19d98ddf..00000000 --- a/src/main/java/FlightBookingTest.java +++ /dev/null @@ -1,89 +0,0 @@ -import com.sun.javafx.PlatformUtil; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.support.ui.Select; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.List; - -public class FlightBookingTest { - - WebDriver driver = new ChromeDriver(); - - - @Test - public void testThatResultsAppearForAOneWayJourney() { - - setDriverPath(); - driver.get("https://www.cleartrip.com/"); - waitFor(2000); - driver.findElement(By.id("OneWay")).click(); - - driver.findElement(By.id("FromTag")).clear(); - driver.findElement(By.id("FromTag")).sendKeys("Bangalore"); - - //wait for the auto complete options to appear for the origin - - waitFor(2000); - List originOptions = driver.findElement(By.id("ui-id-1")).findElements(By.tagName("li")); - originOptions.get(0).click(); - - driver.findElement(By.id("toTag")).clear(); - driver.findElement(By.id("toTag")).sendKeys("Delhi"); - - //wait for the auto complete options to appear for the destination - - waitFor(2000); - //select the first item from the destination auto complete list - List destinationOptions = driver.findElement(By.id("ui-id-2")).findElements(By.tagName("li")); - destinationOptions.get(0).click(); - - driver.findElement(By.xpath("//*[@id='ui-datepicker-div']/div[1]/table/tbody/tr[3]/td[7]/a")).click(); - - //all fields filled in. Now click on search - driver.findElement(By.id("SearchBtn")).click(); - - waitFor(5000); - //verify that result appears for the provided journey search - Assert.assertTrue(isElementPresent(By.className("searchSummary"))); - - //close the browser - driver.quit(); - - } - - - private void waitFor(int durationInMilliSeconds) { - try { - Thread.sleep(durationInMilliSeconds); - } catch (InterruptedException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - } - - - private boolean isElementPresent(By by) { - try { - driver.findElement(by); - return true; - } catch (NoSuchElementException e) { - return false; - } - } - - private void setDriverPath() { - if (PlatformUtil.isMac()) { - System.setProperty("webdriver.chrome.driver", "chromedriver"); - } - if (PlatformUtil.isWindows()) { - System.setProperty("webdriver.chrome.driver", "chromedriver.exe"); - } - if (PlatformUtil.isLinux()) { - System.setProperty("webdriver.chrome.driver", "chromedriver_linux"); - } - } -} diff --git a/src/main/java/HotelBookingTest.java b/src/main/java/HotelBookingTest.java deleted file mode 100644 index 2be026bb..00000000 --- a/src/main/java/HotelBookingTest.java +++ /dev/null @@ -1,53 +0,0 @@ -import com.sun.javafx.PlatformUtil; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.ui.Select; -import org.testng.annotations.Test; - -public class HotelBookingTest { - - WebDriver driver = new ChromeDriver(); - - @FindBy(linkText = "Hotels") - private WebElement hotelLink; - - @FindBy(id = "Tags") - private WebElement localityTextBox; - - @FindBy(id = "SearchHotelsButton") - private WebElement searchButton; - - @FindBy(id = "travellersOnhome") - private WebElement travellerSelection; - - @Test - public void shouldBeAbleToSearchForHotels() { - setDriverPath(); - - driver.get("https://www.cleartrip.com/"); - hotelLink.click(); - - localityTextBox.sendKeys("Indiranagar, Bangalore"); - - new Select(travellerSelection).selectByVisibleText("1 room, 2 adults"); - searchButton.click(); - - driver.quit(); - - } - - private void setDriverPath() { - if (PlatformUtil.isMac()) { - System.setProperty("webdriver.chrome.driver", "chromedriver"); - } - if (PlatformUtil.isWindows()) { - System.setProperty("webdriver.chrome.driver", "chromedriver.exe"); - } - if (PlatformUtil.isLinux()) { - System.setProperty("webdriver.chrome.driver", "chromedriver_linux"); - } - } - -} diff --git a/src/main/java/SignInTest.java b/src/main/java/SignInTest.java deleted file mode 100644 index 2c109950..00000000 --- a/src/main/java/SignInTest.java +++ /dev/null @@ -1,51 +0,0 @@ -import com.sun.javafx.PlatformUtil; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; -import org.testng.Assert; -import org.testng.annotations.Test; - -public class SignInTest { - - WebDriver driver = new ChromeDriver(); - - @Test - public void shouldThrowAnErrorIfSignInDetailsAreMissing() { - - setDriverPath(); - - driver.get("https://www.cleartrip.com/"); - waitFor(2000); - - driver.findElement(By.linkText("Your trips")).click(); - driver.findElement(By.id("SignIn")).click(); - - driver.findElement(By.id("signInButton")).click(); - - String errors1 = driver.findElement(By.id("errors1")).getText(); - Assert.assertTrue(errors1.contains("There were errors in your submission")); - driver.quit(); - } - - private void waitFor(int durationInMilliSeconds) { - try { - Thread.sleep(durationInMilliSeconds); - } catch (InterruptedException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - } - - private void setDriverPath() { - if (PlatformUtil.isMac()) { - System.setProperty("webdriver.chrome.driver", "chromedriver"); - } - if (PlatformUtil.isWindows()) { - System.setProperty("webdriver.chrome.driver", "chromedriver.exe"); - } - if (PlatformUtil.isLinux()) { - System.setProperty("webdriver.chrome.driver", "chromedriver_linux"); - } - } - - -} diff --git a/src/main/java/com/codinground/driverutiils/DriverFactory.java b/src/main/java/com/codinground/driverutiils/DriverFactory.java new file mode 100644 index 00000000..8f475c90 --- /dev/null +++ b/src/main/java/com/codinground/driverutiils/DriverFactory.java @@ -0,0 +1,69 @@ +package com.codinground.driverutiils; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.firefox.FirefoxDriver; + +import com.codinground.ioutils.PropertiesFileUtil; +import com.sun.javafx.PlatformUtil; + +public class DriverFactory { + + protected static WebDriver driver; + private static ChromeOptions options; + + public DriverFactory() { + initialize(); + } + + public void initialize() { + + if (driver == null) + createNewDriverInstance(); + } + + private void createNewDriverInstance() { + String browser = new PropertiesFileUtil().readProperty("browser"); + String driverPathWin =new PropertiesFileUtil().readProperty("driverPathWin"); + String driverPathMac = new PropertiesFileUtil().readProperty("driverPathMac"); + String driverPathLinux = new PropertiesFileUtil().readProperty("driverPathLinux"); + if (browser.equals("firefox")) { + driver = new FirefoxDriver(); + } else if + (browser.equals("chrome")) { + if (PlatformUtil.isMac()) { + System.setProperty("webdriver.chrome.driver", driverPathMac); + } + if (PlatformUtil.isWindows()) { + System.setProperty("webdriver.chrome.driver", driverPathWin); + } + if (PlatformUtil.isLinux()) { + System.setProperty("webdriver.chrome.driver", driverPathLinux); + } + options = new ChromeOptions(); + options.addArguments("--disable-notifications"); + driver = new ChromeDriver(options); + } + + } + + public void launchUrl() { + String url = new PropertiesFileUtil().readProperty("url"); + driver.get(url); + + } + public WebDriver getDriver() { + return driver; + } + + public void destroyDriver() { + driver.quit(); + driver = null; + } + + + + + +} diff --git a/src/main/java/com/codinground/ioutils/PropertiesFileUtil.java b/src/main/java/com/codinground/ioutils/PropertiesFileUtil.java new file mode 100644 index 00000000..2c1a5b9a --- /dev/null +++ b/src/main/java/com/codinground/ioutils/PropertiesFileUtil.java @@ -0,0 +1,29 @@ +package com.codinground.ioutils; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class PropertiesFileUtil { + + Properties properties = new Properties(); + InputStream inputStream = null; + + public PropertiesFileUtil() { + loadProperties(); + } + + private void loadProperties() { + try { + inputStream = new FileInputStream("./src/test/resources/testconfig/uitestconfig.properties"); + properties.load(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String readProperty(String key) { + return properties.getProperty(key); + } +} diff --git a/src/main/java/com/codinground/pages/FlightBookingPage.java b/src/main/java/com/codinground/pages/FlightBookingPage.java new file mode 100644 index 00000000..c277b348 --- /dev/null +++ b/src/main/java/com/codinground/pages/FlightBookingPage.java @@ -0,0 +1,233 @@ +package com.codinground.pages; + + + +import java.util.List; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.LoadableComponent; +import org.testng.Assert; + +import com.codinground.uicommon.UiCommonLibrary; + + + public class FlightBookingPage extends LoadableComponent{ + + + private WebDriver driver; + + private static UiCommonLibrary objCommon; + //private static SimpleDateFormat formatter = new SimpleDateFormat("dd/mmmm/yyyy"); + private static String delimiter = null; + private static String day = null; + private static String month = null; + private static String year = null; + private static String strActualMonth = null; + private static String strActualYear = null; + private static String[] dateArr; + + private static final String STR_DATE_PICKER = "//*[@id='ui-datepicker-div']"; + private static final String STR_MONTH_FIRST_LAST = STR_DATE_PICKER+"/child::div"; + + private static final By LOCATOR_BUTTON_ONEWAY = By.id("OneWay"); + private static final By LOCATOR_INPUT_FROM = By.id("FromTag"); + private static final By LOCATOR_INPUT_FROM_CHECK = By.id("From"); + private static final By LOCATOR_INPUT_TO = By.id("ToTag"); + private static final By LOCATOR_INPUT_TO_CKECK = By.id("To"); + private static final By LOCATOR_BUTTON_SEARCH = By.id("SearchBtn"); + private static final By LOCATOR_MONTH_FIRST_LAST = By.xpath(STR_MONTH_FIRST_LAST); + private static final By LOCATOR_LINK_FLIGHTS = By.linkText("Flights"); + private static final By LOCATOR_LINK_HOTELS = By.linkText("Hotels"); + private static final By LOCATOR_LIST_ORIGIN_OPT = By.xpath("//*[@id='ui-id-1']/li"); + private static final By LOCATOR_LIST_DESTINATION_OPT = By.xpath("//*[@id='ui-id-2']/li"); + private static final By LOCATOR_BUTTON_CALANDER_ICON = By.linkText("Cal"); + private static final By LOCATOR_LINK_YOUR_TRIPS = By.linkText("Your trips"); + private static final By LOCATOR_BUTTON_SIGNIN = By.id("SignIn"); + + private static WebElement btnOneWay; + private static WebElement txtFrom; + private static WebElement txtTo; + private static WebElement btnSearch; + private static WebElement lnkFlights; + private static WebElement lnkHotels; + private static WebElement lnkYourTrips; + private static List elemDayRows; + private static List elemColumns; + private static WebElement actualDay; + private static WebElement txtFromCheck; + private static WebElement txtToCheck; + private static List originOptions; + private static List destinationOptions; + private static List monthFirstLast; + + public FlightBookingPage(WebDriver driver) { + this.driver = driver; + objCommon = new UiCommonLibrary(driver); + } + + + public FlightBookingPage enterDepartFrom(String place) { + for(int i =0; i<+3;i++) { + try { + objCommon.sendKeysOneByOne(LOCATOR_INPUT_FROM,place); + objCommon.waitFor(ExpectedConditions.presenceOfAllElementsLocatedBy(LOCATOR_LIST_ORIGIN_OPT),10); + driver.findElements(LOCATOR_LIST_ORIGIN_OPT).get(0).click(); + break; + }catch(Exception e) { + e.printStackTrace(); + } + } + return this; + } + + public boolean checkIfFromEntered(String excpected) { + + return objCommon.checkIfOptionEntered(LOCATOR_INPUT_FROM_CHECK,excpected); + + } + + public boolean checkIfToEntered(String excpected) { + + return objCommon.checkIfOptionEntered(LOCATOR_INPUT_TO_CKECK,excpected); + + } + + public FlightBookingPage enterToArrive(String place) { + for(int i =0; i<+3;i++) { + try { + objCommon.sendKeysOneByOne(LOCATOR_INPUT_TO,place); + objCommon.waitFor(ExpectedConditions.presenceOfAllElementsLocatedBy(LOCATOR_LIST_DESTINATION_OPT),10); + driver.findElements(LOCATOR_LIST_DESTINATION_OPT).get(0).click(); + break; + }catch(Exception e) { + e.printStackTrace(); + } + } + + return this; + } + + public FlightBookingPage clickOneWay() { + try { + if(objCommon.isElementDisplayed(LOCATOR_BUTTON_ONEWAY)) { + if(!driver.findElement(LOCATOR_BUTTON_ONEWAY).getAttribute("checked").equals("true")) { + objCommon.clickElement(LOCATOR_BUTTON_ONEWAY); + } + } + }catch(Exception e) { + e.printStackTrace(); + } + + return this; + } + + public boolean chechIfOnWayClicked(String expected) { + + return objCommon.checkIfRadioButtonClicked(LOCATOR_BUTTON_ONEWAY,expected); + + } + + public void clickYourTrips() { + + objCommon.clickElement(LOCATOR_LINK_YOUR_TRIPS); + + } + + public SignInPage clickSignInBtn(String name) { + + objCommon.clickElement(LOCATOR_BUTTON_SIGNIN); + //objCommon.switchToFrameByIndex(frameIndex); + objCommon.switchToFrameByNameOrId(name); + + return new SignInPage(driver).get(); + + } + + public SearchSummaryPage clickSearchBtn() { + + if(objCommon.isElementDisplayed(LOCATOR_BUTTON_SEARCH)) { + objCommon.clickElement(LOCATOR_BUTTON_SEARCH); + } + return new SearchSummaryPage(driver).get(); + } + +public HotelBookingPage clickHotelLnk() { + + objCommon.clickElement(LOCATOR_LINK_HOTELS);; + return new HotelBookingPage(driver).get(); + } + + + public void pickFromDate(String date) { + + delimiter= "/"; + dateArr = date.split(delimiter); + day = dateArr[0]; + month = dateArr[1]; + year = dateArr[2]; + monthFirstLast = driver.findElements(LOCATOR_MONTH_FIRST_LAST); + int i=0,j=0,k=0; + for (i=0; i{ + + + private WebDriver driver; + private static UiCommonLibrary objCommon; + private static String delimiter = null; + private static String day = null; + private static String month = null; + private static String year = null; + private static String strActualMonth = null; + private static String strActualYear = null; + private static String[] dateArr; + + private static final By LOCATOR_OPTIONS = By.xpath("//*[@id='ui-id-1']/li"); + private static final String STR_DATE_PICKER = "//*[@id='ui-datepicker-div']"; + private static final String STR_MONTH_FIRST_LAST = STR_DATE_PICKER+"/child::div"; + private static final By LOCATOR_MONTH_FIRST_LAST = By.xpath(STR_MONTH_FIRST_LAST); + private static final By LOCATOR_BUTTON_SEARCH_HOTEL = By.id("SearchHotelsButton"); + + + + @FindBy(linkText = "Hotels") + private static WebElement hotelLink; + + @FindBy(id = "Tags") + private static WebElement localityTextBox; + + @FindBy(id = "SearchHotelsButton") + private static WebElement searchButton; + + @FindBy(id = "travellersOnhome") + private static WebElement travellerSelection; + + private static List elemOptions; + private static List monthFirstLast; + private static List elemDayRows; + private static List elemColumns; + private static WebElement actualDay; + + public HotelBookingPage(WebDriver driver) { + + this.driver = driver; + PageFactory.initElements(driver, this); + objCommon = new UiCommonLibrary(driver); + + } + + public HotelBookingPage clickHotelLnk() { + + hotelLink.click(); + return this; + } + + public HotelBookingPage enterLocationTxt(String place) { + + objCommon.sendKeysOneByOne(By.id("Tags"), place); + objCommon.waitFor(ExpectedConditions.presenceOfAllElementsLocatedBy(LOCATOR_OPTIONS), 10); + driver.findElements(LOCATOR_OPTIONS).get(1).click(); + return this; + } + + public HotelBookingPage selectTravellers(String text) { + objCommon.waitFor(ExpectedConditions.visibilityOf(driver.findElement(By.id("travellersOnhome"))), 10); + objCommon.selectByValue(By.id("travellersOnhome"),text); + return this; + } + + public SearchSummaryPage clickSearchBtn() { + + if(objCommon.isElementDisplayed(LOCATOR_BUTTON_SEARCH_HOTEL)) { + objCommon.clickElement(LOCATOR_BUTTON_SEARCH_HOTEL); + } + return new SearchSummaryPage(driver).get(); + } + + public void pickDate(String date) { + + delimiter= "/"; + dateArr = date.split(delimiter); + day = dateArr[0]; + month = dateArr[1]; + year = dateArr[2]; + monthFirstLast = driver.findElements(LOCATOR_MONTH_FIRST_LAST); + int i=0,j=0,k=0; + for (i=0; i{ + + + private WebDriver driver; + private static WebElement elemSearchSummary; + private static String place; + + private static final By LOCATOR_TITLE_SEARCH_SUMMARY = By.className("searchSummary"); + private static final By LOCATOR_TXT_FROMTO_SEARCH_RESULTS = By.xpath("//*[@class='searchSummary']/*[1]"); + + public SearchSummaryPage(WebDriver driver) { + this.driver = driver; + } + public boolean verifyIfRelevant(String from, String to) { + boolean flag = false; + if(driver.findElement(LOCATOR_TXT_FROMTO_SEARCH_RESULTS).getText().contains(from)&& + driver.findElement(LOCATOR_TXT_FROMTO_SEARCH_RESULTS).getText().contains(to)) { + flag = true; + } + + return flag; + } + + public boolean verifyIfRelevant(String place) { + boolean flag = false; + if(driver.findElement(LOCATOR_TXT_FROMTO_SEARCH_RESULTS).getText().contains(place)) { + flag = true; + } + + return flag; + } + + @Override + protected void load() { + + elemSearchSummary = driver.findElement(LOCATOR_TITLE_SEARCH_SUMMARY); + } + + @Override + protected void isLoaded() throws Error { + + Assert.assertTrue(driver.findElement(LOCATOR_TITLE_SEARCH_SUMMARY).isDisplayed()); + + } + + +} diff --git a/src/main/java/com/codinground/pages/SignInPage.java b/src/main/java/com/codinground/pages/SignInPage.java new file mode 100644 index 00000000..30c2335a --- /dev/null +++ b/src/main/java/com/codinground/pages/SignInPage.java @@ -0,0 +1,57 @@ +package com.codinground.pages; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.LoadableComponent; +import org.testng.Assert; + +import com.codinground.uicommon.UiCommonLibrary; +import com.codinground.uicommon.UiConstants; + +public class SignInPage extends LoadableComponent{ + + private WebDriver driver; + private static WebElement signInBtn; + private static UiCommonLibrary objCommon; + + private static final By LOCATOR_SIGNIN_BUTTON = By.id("signInButton"); + private static final By LOCATOR_ERRORS = By.id("errors1"); + + + public SignInPage(WebDriver driver) { + this.driver=driver; + objCommon = new UiCommonLibrary(driver); + + } + + public SignInPage clickSignIn() { + objCommon.waitFor(ExpectedConditions.visibilityOf(driver.findElement(LOCATOR_SIGNIN_BUTTON)), 10); + objCommon.clickElement(LOCATOR_SIGNIN_BUTTON); + return this; + } + + public boolean verifyErrorMsg() { + + boolean flag = false; + if(driver.findElement(LOCATOR_ERRORS).getText().contains(UiConstants.SIGN_IN_ERROR)) { + flag = true; + } + return flag; + } + + @Override + protected void load() { + signInBtn =driver.findElement(LOCATOR_SIGNIN_BUTTON); + + } + + @Override + protected void isLoaded() throws Error { + objCommon.waitFor(ExpectedConditions.visibilityOf(driver.findElement(LOCATOR_SIGNIN_BUTTON)), 10); + Assert.assertTrue(driver.findElement(LOCATOR_SIGNIN_BUTTON).isDisplayed()); + + } + +} diff --git a/src/main/java/com/codinground/reportutils/ReportListener.java b/src/main/java/com/codinground/reportutils/ReportListener.java new file mode 100644 index 00000000..3a532259 --- /dev/null +++ b/src/main/java/com/codinground/reportutils/ReportListener.java @@ -0,0 +1,101 @@ +package com.codinground.reportutils; + + + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import org.apache.commons.io.FileUtils; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; + + +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; + +import com.codinground.driverutiils.DriverFactory; +import com.relevantcodes.extentreports.ExtentReports; +import com.relevantcodes.extentreports.ExtentTest; +import com.relevantcodes.extentreports.LogStatus; + + +public class ReportListener implements ITestListener { + + + + protected static ExtentReports reports; + protected static ExtentTest test; + private ITestContext context; + private DriverFactory objDriverFac = new DriverFactory(); + + public void onTestStart(ITestResult result) { + System.out.println("on test start"); + test = reports.startTest(result.getMethod().getMethodName()); + test.log(LogStatus.INFO, result.getMethod().getMethodName() + "test is started"); + } + + public void onTestSuccess(ITestResult result) { + System.out.println("on test success"); + test.log(LogStatus.PASS, result.getMethod().getMethodName() + "test is passed"); + TakesScreenshot ts = (TakesScreenshot) objDriverFac.getDriver(); + File src = ts.getScreenshotAs(OutputType.FILE); + try { + FileUtils.copyFile(src, new File(System.getProperty("user.dir") + "\\ExtentReports\\"+context.getName()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"_passed.png")); + // String file = test.addScreenCapture("./" + result.getTestName()+result.getMethod().getMethodName() + ".png"); + String file = test.addScreenCapture(System.getProperty("user.dir") + "\\ExtentReports\\"+context.getName()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"_passed.png"); + System.out.println("**********************************=======================================************************************************"); + test.log(LogStatus.PASS, result.getMethod().getMethodName() + "test passed", file); + test.log(LogStatus.PASS, result.getMethod().getMethodName() + "test passed"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + + public void onTestFailure(ITestResult result) { + System.out.println("on test failure"); + test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test is failed"); + TakesScreenshot ts = (TakesScreenshot) objDriverFac.getDriver(); + File src = ts.getScreenshotAs(OutputType.FILE); + try { + FileUtils.copyFile(src, new File(System.getProperty("user.dir") + "\\ExtentReports\\"+context.getName()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"_failed.png")); + String file = test.addScreenCapture(System.getProperty("user.dir") + "\\ExtentReports\\"+context.getName()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"_failed.png"); + System.out.println("**********************************=======================================************************************************"); + test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test failed", file); + test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test failed", result.getThrowable().getMessage()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public void onTestSkipped(ITestResult result) { + System.out.println("on test skipped"); + test.log(LogStatus.SKIP, result.getMethod().getMethodName() + "test is skipped"); + } + + + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + System.out.println("on test sucess within percentage"); + } + + + public void onStart(ITestContext context) { + System.out.println("on start"); + String workingDir = System.getProperty("user.dir"); + this.context = context; + reports = new ExtentReports(workingDir + "\\ExtentReports\\"+context.getName()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"_ExtentReportResults.html",true); + + } + + + public void onFinish(ITestContext context) { + System.out.println("on finish"); + reports.endTest(test); + reports.flush(); + } +} + diff --git a/src/main/java/com/codinground/testrunutils/AddAnnotations.java b/src/main/java/com/codinground/testrunutils/AddAnnotations.java new file mode 100644 index 00000000..1a8f53eb --- /dev/null +++ b/src/main/java/com/codinground/testrunutils/AddAnnotations.java @@ -0,0 +1,17 @@ +package com.codinground.testrunutils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import org.testng.IAnnotationTransformer; +import org.testng.annotations.ITestAnnotation; + +public class AddAnnotations implements IAnnotationTransformer{ + + public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { + + annotation.setRetryAnalyzer(RetryFailed.class); + + } + +} diff --git a/src/main/java/com/codinground/testrunutils/RetryFailed.java b/src/main/java/com/codinground/testrunutils/RetryFailed.java new file mode 100644 index 00000000..5df3ebc8 --- /dev/null +++ b/src/main/java/com/codinground/testrunutils/RetryFailed.java @@ -0,0 +1,24 @@ +package com.codinground.testrunutils; + +import org.testng.IRetryAnalyzer; +import org.testng.ITestResult; + +import com.codinground.ioutils.PropertiesFileUtil; + +public class RetryFailed implements IRetryAnalyzer{ + + private PropertiesFileUtil objProperty = new PropertiesFileUtil(); + private int counter =0; + private String retriesLimiter = objProperty.readProperty("numberOfRetriesFailed"); + + public boolean retry(ITestResult result) { + //&&(!result.isSuccess()) + + while(counter void waitFor(ExpectedCondition expectedConditions,int timeOut) { + + new WebDriverWait(driver, timeOut).until(expectedConditions); + + } + + /*public String alertHandler(String operation) { + + alert = driver.switchTo().alert(); + String strToReturn = null; + + switch(operation) { + case"dissmis": + alert.dismiss(); + strToReturn = alert.getText()+": Alert Dissmissed"; + case"accept": + alert.accept(); + strToReturn = alert.getText()+": Alert Accepted"; + case"getText": + alert.getText(); + strToReturn = "Alert Text: "+alert.getText(); + } + return strToReturn; + }*/ + + public void clickElement(By xpath) { + + driver.findElement(xpath).click(); + + } + + public boolean isElementDisplayed(By xpath) { + boolean state= false; + state = driver.findElement(xpath).isDisplayed(); + return state; + } + + public void implictWaitOn() { + + driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); + + } + + public void implicitWaitOff() { + + driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); + + } + + /*public void selectValue(By xpath, String value, String method) { + + select = new Select(driver.findElement(xpath)); + + switch (method) { + + case "byIndex": + + select.selectByIndex(Integer.valueOf(value)); + + case "byValue": + + select.selectByValue(value); + + case "byVisibleText": + + select.selectByVisibleText(value); + } + }*/ + + public void selectByValue(By xpath, String value) { + + select = new Select(driver.findElement(xpath)); + select.selectByVisibleText(value); + } + + public boolean checkIfOptionEntered(By xpath, String expected) { + boolean flag=false; + waitFor(ExpectedConditions.presenceOfElementLocated(xpath), 10); + if(driver.findElement(xpath).getAttribute("value").equalsIgnoreCase(expected)) { + flag=true; + } + return flag; + } + + public boolean checkIfRadioButtonClicked(By xpath, String expected) { + boolean flag=false; + waitFor(ExpectedConditions.presenceOfElementLocated(xpath), 10); + if(driver.findElement(xpath).getAttribute("checked").equalsIgnoreCase(expected)) { + flag=true; + } + return flag; + } + } + + + + + + + diff --git a/src/main/java/com/codinground/uicommon/UiConstants.java b/src/main/java/com/codinground/uicommon/UiConstants.java new file mode 100644 index 00000000..ec98474e --- /dev/null +++ b/src/main/java/com/codinground/uicommon/UiConstants.java @@ -0,0 +1,11 @@ + +package com.codinground.uicommon; + +public class UiConstants { + + public static final String BANGALORE = "BLR"; + public static final String NEW_DELHI = "DEL"; + public static final String ATTRIBUTE_CHECKED = "true"; + public static final String SIGN_IN_ERROR = "There were errors in your submission"; + +} diff --git a/src/main/resources/com/codinground/dummy_ignore/Dummy.java b/src/main/resources/com/codinground/dummy_ignore/Dummy.java new file mode 100644 index 00000000..f72b9712 --- /dev/null +++ b/src/main/resources/com/codinground/dummy_ignore/Dummy.java @@ -0,0 +1,10 @@ +package com.codinground.dummy_ignore; + +/** + * Added to avoid missing src/main/resources error on importing + * has no dependencies + * can be removed +*/ +public class Dummy { + +} diff --git a/src/test/java/com/codinground/tests/FlightBookingTest.java b/src/test/java/com/codinground/tests/FlightBookingTest.java new file mode 100644 index 00000000..8efdd779 --- /dev/null +++ b/src/test/java/com/codinground/tests/FlightBookingTest.java @@ -0,0 +1,63 @@ +package com.codinground.tests; +import com.codinground.driverutiils.DriverFactory; +import com.codinground.pages.FlightBookingPage; +import com.codinground.pages.SearchSummaryPage; +import com.codinground.reportutils.ReportListener; +import com.codinground.uicommon.UiConstants; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.openqa.selenium.WebDriver; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + + + +public class FlightBookingTest extends ReportListener { + + + + + private WebDriver driver; + private static FlightBookingPage objFlightPage; + private static DriverFactory objDriverFactory; + private static SearchSummaryPage objSearchSummaryPage; + private static ReportListener objReportListener; + + @BeforeTest + public void before() { + objDriverFactory = new DriverFactory(); + objDriverFactory.launchUrl(); + driver = objDriverFactory.getDriver(); + driver.manage().window().maximize(); + + } + + @Test + public void testThatResultsAppearForAOneWayJourney() { + + objFlightPage = new FlightBookingPage(driver).get(); + + objFlightPage = objFlightPage.clickOneWay(); + Assert.assertTrue(objFlightPage.chechIfOnWayClicked(UiConstants.ATTRIBUTE_CHECKED)); + objFlightPage = objFlightPage.enterDepartFrom("Bangalore"); + Assert.assertTrue(objFlightPage.checkIfFromEntered(UiConstants.BANGALORE)); + objFlightPage = objFlightPage.enterToArrive("New Delhi"); + Assert.assertTrue(objFlightPage.checkIfToEntered(UiConstants.NEW_DELHI)); + objFlightPage = new FlightBookingPage(driver).get(); + objFlightPage.pickFromDate(new SimpleDateFormat("d/MMMM/yyyy").format(new Date())); + objSearchSummaryPage = objFlightPage.clickSearchBtn(); + Assert.assertTrue(objSearchSummaryPage.verifyIfRelevant("Bangalore", "New Delhi")); + } + + @AfterTest + public void after() { + + objDriverFactory.destroyDriver(); + + } + +} diff --git a/src/test/java/com/codinground/tests/HotelBookingTest.java b/src/test/java/com/codinground/tests/HotelBookingTest.java new file mode 100644 index 00000000..07a7de10 --- /dev/null +++ b/src/test/java/com/codinground/tests/HotelBookingTest.java @@ -0,0 +1,67 @@ +package com.codinground.tests; +import com.codinground.driverutiils.DriverFactory; +import com.codinground.pages.FlightBookingPage; +import com.codinground.pages.HotelBookingPage; +import com.codinground.pages.SearchSummaryPage; +import com.codinground.reportutils.ReportListener; +import com.codinground.uicommon.UiCommonLibrary; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import org.openqa.selenium.WebDriver; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class HotelBookingTest extends ReportListener{ + + private WebDriver driver; + private static Date today; + private static Calendar cal; + private static String date; + private static HotelBookingPage objHotelPage; + private static DriverFactory objDriverFactory; + private static SearchSummaryPage objSearchSummaryPage; + private static FlightBookingPage objFlightPage; + + @BeforeTest + public void before() { + objDriverFactory = new DriverFactory(); + objDriverFactory.launchUrl(); + driver = objDriverFactory.getDriver(); + driver.manage().window().maximize(); + } + @Test + public void shouldBeAbleToSearchForHotels() throws InterruptedException { + + objFlightPage = new FlightBookingPage(driver).get(); + objHotelPage = objFlightPage.clickHotelLnk(); + objHotelPage = objHotelPage.enterLocationTxt("Indiranagar, Bangalore"); + objHotelPage.pickDate(new SimpleDateFormat("d/MMMM/yyyy").format(new Date())); + /*pick the next day*/ + today = new Date(); + cal = Calendar.getInstance(); + cal.setTime(today); + cal.add(Calendar.DATE, 1); + today = cal.getTime(); + date = new SimpleDateFormat("d/MMMM/yyyy").format(today); + objHotelPage.pickDate(date); + objHotelPage = objHotelPage.selectTravellers("1 room, 2 adults"); + objSearchSummaryPage = objHotelPage.clickSearchBtn(); + Assert.assertTrue(objSearchSummaryPage.verifyIfRelevant("Bangalore")); + + } + + + @AfterTest + public void after() { + + objDriverFactory.destroyDriver(); + + } + + +} diff --git a/src/test/java/com/codinground/tests/SignInTest.java b/src/test/java/com/codinground/tests/SignInTest.java new file mode 100644 index 00000000..66257d6a --- /dev/null +++ b/src/test/java/com/codinground/tests/SignInTest.java @@ -0,0 +1,49 @@ +package com.codinground.tests; +import org.openqa.selenium.WebDriver; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.codinground.driverutiils.DriverFactory; +import com.codinground.pages.FlightBookingPage; +import com.codinground.pages.SignInPage; +import com.codinground.reportutils.ReportListener; + +public class SignInTest extends ReportListener{ + + private WebDriver driver; + private static DriverFactory objDriverFactory; + private static FlightBookingPage objFlightPage; + private static SignInPage objSignInPage; + + + @BeforeTest + public void beforeTest() { + objDriverFactory = new DriverFactory(); + objDriverFactory.launchUrl(); + driver = objDriverFactory.getDriver(); + objSignInPage = new SignInPage(driver); + driver.manage().window().maximize(); + } + + @Test + public void shouldThrowAnErrorIfSignInDetailsAreMissing() { + + objFlightPage = new FlightBookingPage(driver).get(); + objFlightPage.clickYourTrips(); + objSignInPage = objFlightPage.clickSignInBtn("modal_window"); + objSignInPage.clickSignIn(); + Assert.assertTrue(objSignInPage.verifyErrorMsg()); + + + + } + + @AfterTest + public void afterTest() { + objDriverFactory.destroyDriver(); + + } + +} diff --git a/src/test/resources/testconfig/uitestconfig.properties b/src/test/resources/testconfig/uitestconfig.properties new file mode 100644 index 00000000..25a96038 --- /dev/null +++ b/src/test/resources/testconfig/uitestconfig.properties @@ -0,0 +1,6 @@ +browser=chrome +driverPathWin=./drivers/chromedriver_win.exe +driverPathMac=./drivers/chromedriver_mac +driverPathLinux=./drivers/chromedriver_Linux +url=https://www.cleartrip.com/ +numberOfRetriesFailed=2 \ No newline at end of file diff --git a/testng.xml b/testng.xml new file mode 100644 index 00000000..80b06bff --- /dev/null +++ b/testng.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + +