From a355087470167edfac5eac6f0674e6d9ec047030 Mon Sep 17 00:00:00 2001 From: Sergey Zozulya Date: Thu, 24 Jun 2021 20:16:19 +0300 Subject: [PATCH] Add "Bring It On" and "Hardcore" levels tasks --- README.md | 1 + pom.xml | 32 ++++ .../java/BringItOn/page/AbstractPage.java | 22 +++ .../java/BringItOn/page/PastebinMainPage.java | 73 +++++++++ .../page/PastebinSubmittedPastePage.java | 25 +++ .../java/BringItOn/test/AbstractTest.java | 50 ++++++ .../java/BringItOn/test/PastebinTest.java | 30 ++++ src/test/java/Hardcore/page/AbstractPage.java | 43 ++++++ .../Hardcore/page/GoogleCloudMainPage.java | 39 +++++ .../GoogleCloudPricingCalculatorPage.java | 142 ++++++++++++++++++ .../java/Hardcore/page/TempEmailPage.java | 36 +++++ src/test/java/Hardcore/test/AbstractTest.java | 22 +++ .../java/Hardcore/test/GoogleCloudTest.java | 45 ++++++ 13 files changed, 560 insertions(+) create mode 100644 pom.xml create mode 100644 src/test/java/BringItOn/page/AbstractPage.java create mode 100644 src/test/java/BringItOn/page/PastebinMainPage.java create mode 100644 src/test/java/BringItOn/page/PastebinSubmittedPastePage.java create mode 100644 src/test/java/BringItOn/test/AbstractTest.java create mode 100644 src/test/java/BringItOn/test/PastebinTest.java create mode 100644 src/test/java/Hardcore/page/AbstractPage.java create mode 100644 src/test/java/Hardcore/page/GoogleCloudMainPage.java create mode 100644 src/test/java/Hardcore/page/GoogleCloudPricingCalculatorPage.java create mode 100644 src/test/java/Hardcore/page/TempEmailPage.java create mode 100644 src/test/java/Hardcore/test/AbstractTest.java create mode 100644 src/test/java/Hardcore/test/GoogleCloudTest.java diff --git a/README.md b/README.md index 11759e6..2b38b6e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # EPAM FTM Advanced Program - Selenium WebDriver +https://elearn.epam.com/courses/course-v1:EPAM+WD+ext1/course/ ## Bring It On При выполнении задания необходимо использовать возможности Selenium WebDriver, юнит-тест фреймворка и концепцию Page Object. Автоматизировать следующий сценарий: 1. Открыть https://pastebin.com или аналогичный сервис в любом браузере. diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f3ce094 --- /dev/null +++ b/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + com.epam.ftm.selenium.webdriver + epam-ftm-selenium-webdriver + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + org.seleniumhq.selenium + selenium-java + 3.141.59 + + + + org.testng + testng + 7.4.0 + test + + + + \ No newline at end of file diff --git a/src/test/java/BringItOn/page/AbstractPage.java b/src/test/java/BringItOn/page/AbstractPage.java new file mode 100644 index 0000000..d771782 --- /dev/null +++ b/src/test/java/BringItOn/page/AbstractPage.java @@ -0,0 +1,22 @@ +package BringItOn.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +public abstract class AbstractPage { + protected WebDriver driver; + + protected final int WAIT_TIMEOUT_SECONDS = 10; + + protected AbstractPage(WebDriver driver) { + this.driver = driver; + PageFactory.initElements(driver, this); + } + + protected WebElement waitForWebElementVisible(WebElement element) { + return new WebDriverWait(driver, WAIT_TIMEOUT_SECONDS).until(ExpectedConditions.visibilityOf(element)); + } +} diff --git a/src/test/java/BringItOn/page/PastebinMainPage.java b/src/test/java/BringItOn/page/PastebinMainPage.java new file mode 100644 index 0000000..40014f9 --- /dev/null +++ b/src/test/java/BringItOn/page/PastebinMainPage.java @@ -0,0 +1,73 @@ +package BringItOn.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.ui.WebDriverWait; + +public class PastebinMainPage extends AbstractPage { + private final String BASE_URL = "https://pastebin.com"; + + @FindBy(id = "postform-text") + WebElement textAreaNewPaste; + + @FindBy(id = "select2-postform-format-container") + WebElement syntaxDropdown; + @FindBy(xpath = "//li[text()='Bash']") + WebElement syntaxBash; + + @FindBy(id = "select2-postform-expiration-container") + WebElement expirationDropdown; + @FindBy(xpath = "//li[text()='10 Minutes']") + WebElement expiration10M; + + @FindBy(id = "postform-name") + WebElement inputTitle; + + @FindBy(xpath = "//button[@type='submit']") + WebElement buttonNewPaste; + + public PastebinMainPage(WebDriver driver) { + super(driver); + } + + public PastebinMainPage openPage() { + driver.get(BASE_URL); + return this; + } + + public PastebinMainPage typeInNewPasteText(String newPasteText) { + waitForWebElementVisible(textAreaNewPaste).sendKeys(newPasteText); + return this; + } + + public PastebinMainPage openSyntaxDropdown() { + syntaxDropdown.click(); + return this; + } + + public PastebinMainPage selectSyntaxBash() { + syntaxBash.click(); + return this; + } + + public PastebinMainPage openExpirationDropdown() { + expirationDropdown.click(); + return this; + } + + public PastebinMainPage selectExpiration10M() { + expiration10M.click(); + return this; + } + + public PastebinMainPage typeInNewPasteTitle(String newPasteTitle) { + inputTitle.sendKeys(newPasteTitle); + return this; + } + + public PastebinMainPage submitNewPaste() { + buttonNewPaste.click(); + return this; + } +} diff --git a/src/test/java/BringItOn/page/PastebinSubmittedPastePage.java b/src/test/java/BringItOn/page/PastebinSubmittedPastePage.java new file mode 100644 index 0000000..dc2f36f --- /dev/null +++ b/src/test/java/BringItOn/page/PastebinSubmittedPastePage.java @@ -0,0 +1,25 @@ +package BringItOn.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class PastebinSubmittedPastePage extends AbstractPage { + @FindBy(xpath = "//div[@class='left']/a[text()='Bash']") + WebElement syntaxSubmittedPaste; + + @FindBy(xpath = "//textarea") + WebElement textSubmittedPaste; + + public PastebinSubmittedPastePage(WebDriver driver) { + super(driver); + } + + public String getSyntaxSubmittedPaste() { + return syntaxSubmittedPaste.getText(); + } + + public String getSubmittedPasteText() { + return textSubmittedPaste.getText(); + } +} diff --git a/src/test/java/BringItOn/test/AbstractTest.java b/src/test/java/BringItOn/test/AbstractTest.java new file mode 100644 index 0000000..a15c34b --- /dev/null +++ b/src/test/java/BringItOn/test/AbstractTest.java @@ -0,0 +1,50 @@ +package BringItOn.test; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.annotations.*; +import BringItOn.page.PastebinMainPage; +import BringItOn.page.PastebinSubmittedPastePage; + +public abstract class AbstractTest { + protected WebDriver driver; + + protected static final String NEW_PASTE_TEXT = "git config --global user.name \"New Sheriff in Town\"\n" + + "git reset $(git commit-tree HEAD^{tree} -m \"Legacy code\")\n" + + "git push origin master --force"; + protected static final String NEW_PASTE_TITLE = "how to gain dominance among developers"; + protected static final String SUBMITTED_PASTE_TITLE_LOCATOR = "//div[@class='info-top']/h1"; + protected static final String EXPECTED_PASTE_SYNTAX = "Bash"; + PastebinMainPage pastebinMainPage; + PastebinSubmittedPastePage pastebinSubmittedPastePage; + + @BeforeTest(alwaysRun = true) + public void browserSetup() { + driver = new ChromeDriver(); + driver.manage().window().maximize(); + pastebinMainPage = new PastebinMainPage(driver) + .openPage() + .typeInNewPasteText(NEW_PASTE_TEXT) + .openSyntaxDropdown() + .selectSyntaxBash() + .openExpirationDropdown() + .selectExpiration10M() + .typeInNewPasteTitle(NEW_PASTE_TITLE) + .submitNewPaste(); + pastebinSubmittedPastePage = new PastebinSubmittedPastePage(driver); + } + + public WebElement waitForElement(By by) { + return new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(by)); + } + + @AfterTest(alwaysRun = true) + public void browserExit() { + driver.quit(); + driver = null; + } +} diff --git a/src/test/java/BringItOn/test/PastebinTest.java b/src/test/java/BringItOn/test/PastebinTest.java new file mode 100644 index 0000000..af6bb8f --- /dev/null +++ b/src/test/java/BringItOn/test/PastebinTest.java @@ -0,0 +1,30 @@ +package BringItOn.test; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class PastebinTest extends AbstractTest { + @Test(description = "Check if submitted paste title matches initial paste title") + public void checkSubmittedPastePageTitle() { + WebElement titleSubmittedPaste = waitForElement(By.xpath(SUBMITTED_PASTE_TITLE_LOCATOR)); + String actualPageTitle = titleSubmittedPaste.getText(); + + Assert.assertEquals(actualPageTitle, NEW_PASTE_TITLE, "Submitted paste title doesn't match initial paste title"); + } + + @Test(description = "Check if syntax highlighting is Bash") + public void checkSubmittedPasteSyntaxHighlighting() { + String actualSyntax = pastebinSubmittedPastePage.getSyntaxSubmittedPaste(); + + Assert.assertEquals(actualSyntax, EXPECTED_PASTE_SYNTAX, "Submitted paste syntax highlighting is not Bash"); + } + + @Test(description = "Check if submitted paste text matches initial text") + public void checkSubmittedPasteText() { + String actualText = pastebinSubmittedPastePage.getSubmittedPasteText(); + + Assert.assertEquals(actualText, NEW_PASTE_TEXT, "Submitted paste text doesn't match initial paste text"); + } +} diff --git a/src/test/java/Hardcore/page/AbstractPage.java b/src/test/java/Hardcore/page/AbstractPage.java new file mode 100644 index 0000000..53d5b3e --- /dev/null +++ b/src/test/java/Hardcore/page/AbstractPage.java @@ -0,0 +1,43 @@ +package Hardcore.page; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.util.ArrayList; + +public abstract class AbstractPage { + protected WebDriver driver; + + protected final int WAIT_TIMEOUT_SECONDS = 10; + + protected AbstractPage(WebDriver driver) { + this.driver = driver; + PageFactory.initElements(driver, this); + } + + protected WebElement waitForWebElementVisible(WebElement element) { + return new WebDriverWait(driver, WAIT_TIMEOUT_SECONDS).until(ExpectedConditions.visibilityOf(element)); + } + + protected void openNewTab() { + ((JavascriptExecutor) driver).executeScript("window.open()"); + } + + public void switchToPreviousTab() { + ArrayList tabs = new ArrayList<>(driver.getWindowHandles()); + String currentTab = driver.getWindowHandle(); + int currentTabIndex = tabs.indexOf(currentTab); + driver.switchTo().window(tabs.get(currentTabIndex - 1)); + } + + public void switchToNextTab() { + ArrayList tabs = new ArrayList<>(driver.getWindowHandles()); + String currentTab = driver.getWindowHandle(); + int currentTabIndex = tabs.indexOf(currentTab); + driver.switchTo().window(tabs.get(currentTabIndex + 1)); + } +} \ No newline at end of file diff --git a/src/test/java/Hardcore/page/GoogleCloudMainPage.java b/src/test/java/Hardcore/page/GoogleCloudMainPage.java new file mode 100644 index 0000000..9459f05 --- /dev/null +++ b/src/test/java/Hardcore/page/GoogleCloudMainPage.java @@ -0,0 +1,39 @@ +package Hardcore.page; + +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class GoogleCloudMainPage extends AbstractPage { + String GC_BASE_URL = "https://cloud.google.com/"; + + @FindBy(name = "q") + WebElement searchInput; + + @FindBy(xpath = "//div[@class='devsite-cse-results']") + WebElement resultsPage; + + @FindBy(xpath = "//b[text()='Google Cloud Platform Pricing Calculator']") + WebElement resultPattern; + + public GoogleCloudMainPage(WebDriver driver) { + super(driver); + } + + public GoogleCloudMainPage openPage() { + driver.get(GC_BASE_URL); + return this; + } + + public GoogleCloudMainPage searchTerm(String term) { + waitForWebElementVisible(searchInput).sendKeys(term + Keys.ENTER); + return this; + } + + public GoogleCloudMainPage clickCalculatorPage() { + waitForWebElementVisible(resultsPage); + waitForWebElementVisible(resultPattern).click(); + return this; + } +} diff --git a/src/test/java/Hardcore/page/GoogleCloudPricingCalculatorPage.java b/src/test/java/Hardcore/page/GoogleCloudPricingCalculatorPage.java new file mode 100644 index 0000000..b6e9f8e --- /dev/null +++ b/src/test/java/Hardcore/page/GoogleCloudPricingCalculatorPage.java @@ -0,0 +1,142 @@ +package Hardcore.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class GoogleCloudPricingCalculatorPage extends AbstractPage { + + @FindBy(xpath = "//iframe[contains(@src, '/products/calculator')]") + WebElement frameMain; + + @FindBy(xpath = "//md-tab-item[@aria-controls='tab-content-1']") + WebElement buttonComputeEngine; + + @FindBy(xpath = "//input[@ng-model='listingCtrl.computeServer.quantity']") + WebElement inputNumberOfInstances; + + @FindBy(xpath = "//input[@ng-model='listingCtrl.computeServer.label']") + WebElement inputPurpose; + + @FindBy(xpath = "//md-select[@ng-model='listingCtrl.computeServer.os']") + WebElement dropdownSoftware; + @FindBy(xpath = "//md-option[@value='free']") + WebElement itemSoftware; + + @FindBy(xpath = "//md-select[@ng-model='listingCtrl.computeServer.class']") + WebElement dropdownClass; + @FindBy(xpath = "//md-select-menu[@style]/descendant::md-option[@value='regular']") + WebElement itemClass; + + @FindBy(xpath = "//md-select[@name='series']") + WebElement dropdownSeries; + @FindBy(xpath = "//md-option[@value='n1']") + WebElement itemSeries; + + @FindBy(xpath = "//md-select[@placeholder='Instance type']") + WebElement dropdownMachineType; + @FindBy(xpath = "//md-option[@value='CP-COMPUTEENGINE-VMIMAGE-N1-STANDARD-8']") + WebElement itemMachineType; + + @FindBy(xpath = "//md-checkbox[@aria-label='Add GPUs' and @ng-model='listingCtrl.computeServer.addGPUs']") + WebElement checkboxAddGPUs; + @FindBy(xpath = "//md-select[@placeholder='Number of GPUs']") + WebElement dropboxNumberOfGPUs; + @FindBy(xpath = "//md-option[@value='1' and contains(@ng-repeat, 'gpuType')]") + WebElement itemNumberOfGPUs; + @FindBy(xpath = "//md-select[@placeholder='GPU type']") + WebElement dropboxGPUType; + @FindBy(xpath = "//md-option[@value='NVIDIA_TESLA_V100']") + WebElement itemGPUType; + + @FindBy(xpath = "//md-select[@placeholder='Local SSD']") + WebElement dropdownSSD; + @FindBy(xpath = "//md-option[@value='2' and contains(@ng-repeat, 'item in listingCtrl.dynamicSsd.computeServer')]") + WebElement itemSSD; + + @FindBy(xpath = "//md-select[@placeholder='Datacenter location'][@ng-model='listingCtrl.computeServer.location']") + WebElement dropdownLocation; + @FindBy(xpath = "//md-select-menu[@class='md-overflow']/descendant::md-option[@value='europe-west3' and contains(@ng-repeat, 'item in listingCtrl.fullRegionList')]") + WebElement itemLocation; + + @FindBy(xpath = "//md-select[@placeholder='Committed usage']") + WebElement dropdownUsage; + @FindBy(xpath = "//div[@class='md-select-menu-container md-active md-clickable']/descendant::md-option[@ng-value='1'][@value='1']") + WebElement itemUsage; + + @FindBy(xpath = "//button[@aria-label='Add to Estimate' and contains(@ng-click, 'addComputeServer')]") + WebElement buttonAddToEstimate; + + @FindBy(xpath = "//h2/b[@class='ng-binding']") + WebElement textTotalCost; + + @FindBy(xpath = "//button[@aria-label='Email Estimate']") + WebElement buttonEmailEstimate; + + @FindBy(xpath = "//input[@ng-model='emailQuote.user.email']") + WebElement inputEmail; + + @FindBy(xpath = "//button[@aria-label='Send Email']") + WebElement buttonSendEmail; + + public GoogleCloudPricingCalculatorPage(WebDriver driver) { + super(driver); + } + + public GoogleCloudPricingCalculatorPage switchToCalculatorIFrame() { + driver.switchTo().frame(frameMain); + driver.switchTo().frame("myFrame"); + return this; + } + + public GoogleCloudPricingCalculatorPage fillInEstimationForm() { + String instances = "4"; + + waitForWebElementVisible(buttonComputeEngine).click(); + inputNumberOfInstances.sendKeys(instances); + inputPurpose.clear(); + dropdownSoftware.click(); + waitForWebElementVisible(itemSoftware).click(); + dropdownClass.click(); + waitForWebElementVisible(itemClass).click(); + dropdownSeries.click(); + waitForWebElementVisible(itemSeries).click(); + dropdownMachineType.click(); + waitForWebElementVisible(itemMachineType).click(); + checkboxAddGPUs.click(); + waitForWebElementVisible(dropboxNumberOfGPUs).click(); + waitForWebElementVisible(itemNumberOfGPUs).click(); + dropboxGPUType.click(); + waitForWebElementVisible(itemGPUType).click(); + dropdownSSD.click(); + waitForWebElementVisible(itemSSD).click(); + dropdownLocation.click(); + waitForWebElementVisible(itemLocation).click(); + dropdownUsage.click(); + waitForWebElementVisible(itemUsage).click(); + return this; + } + + public GoogleCloudPricingCalculatorPage clickAddToEstimateButton() { + buttonAddToEstimate.click(); + return this; + } + + public String getTotalCost() { + return waitForWebElementVisible(textTotalCost).getText(); + } + + public GoogleCloudPricingCalculatorPage clickEmailEstimateButton() { + buttonEmailEstimate.click(); + return this; + } + + public GoogleCloudPricingCalculatorPage enterTempEMail(String tempEmail) { + waitForWebElementVisible(inputEmail).sendKeys(tempEmail); + return this; + } + + public void sendEmail() { + buttonSendEmail.click(); + } +} diff --git a/src/test/java/Hardcore/page/TempEmailPage.java b/src/test/java/Hardcore/page/TempEmailPage.java new file mode 100644 index 0000000..b0c7373 --- /dev/null +++ b/src/test/java/Hardcore/page/TempEmailPage.java @@ -0,0 +1,36 @@ +package Hardcore.page; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class TempEmailPage extends AbstractPage { + // Using another service here since I'm getting error right away after opening 10minutemail.com + // It used to work initially, but now it doesn't (banned by IP??) + String TEMP_EMAIL_URL = "https://generator.email/email-generator"; + + @FindBy(id = "email_ch_text") + WebElement fieldTempEmail; + + @FindBy(xpath = "//h3[contains(text(), 'USD')]") + WebElement priceAmount; + + public TempEmailPage(WebDriver driver) { + super(driver); + } + + public TempEmailPage openInNewTab() { + openNewTab(); + switchToNextTab(); + driver.get(TEMP_EMAIL_URL); + return this; + } + + public String getTempEMail() { + return waitForWebElementVisible(fieldTempEmail).getText(); + } + + public String getCostFromEmail() { + return waitForWebElementVisible(priceAmount).getText(); + } +} diff --git a/src/test/java/Hardcore/test/AbstractTest.java b/src/test/java/Hardcore/test/AbstractTest.java new file mode 100644 index 0000000..f20814c --- /dev/null +++ b/src/test/java/Hardcore/test/AbstractTest.java @@ -0,0 +1,22 @@ +package Hardcore.test; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; + +public class AbstractTest { + protected WebDriver driver; + + @BeforeTest(alwaysRun = true) + public void browserSetup() { + driver = new ChromeDriver(); + driver.manage().window().maximize(); + } + + @AfterTest(alwaysRun = true) + public void browserExit() { + driver.quit(); + driver = null; + } +} diff --git a/src/test/java/Hardcore/test/GoogleCloudTest.java b/src/test/java/Hardcore/test/GoogleCloudTest.java new file mode 100644 index 0000000..7345736 --- /dev/null +++ b/src/test/java/Hardcore/test/GoogleCloudTest.java @@ -0,0 +1,45 @@ +package Hardcore.test; + +import Hardcore.page.GoogleCloudMainPage; +import Hardcore.page.GoogleCloudPricingCalculatorPage; +import Hardcore.page.TempEmailPage; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class GoogleCloudTest extends AbstractTest { + GoogleCloudMainPage cloudMainPage; + String SEARCH_TERM_MAIN_PAGE = "Google Cloud Platform Pricing Calculator"; + GoogleCloudPricingCalculatorPage cloudCalculatorPage; + TempEmailPage tempEmailPage; + + @Test(description = "Fill in estimation form") + public void fillInEstimationForm() { + cloudMainPage = new GoogleCloudMainPage(driver) + .openPage() + .searchTerm(SEARCH_TERM_MAIN_PAGE) + .clickCalculatorPage(); + cloudCalculatorPage = new GoogleCloudPricingCalculatorPage(driver) + .switchToCalculatorIFrame() + .fillInEstimationForm() + .clickAddToEstimateButton(); + } + + @Test(dependsOnMethods = {"fillInEstimationForm"}, + description = "Check Email total cost against calculated total cost") + public void checkTotalCost() { + tempEmailPage = new TempEmailPage(driver).openInNewTab(); + String tempEmail = tempEmailPage.getTempEMail(); + + cloudCalculatorPage.switchToPreviousTab(); + cloudCalculatorPage.switchToCalculatorIFrame() + .clickEmailEstimateButton() + .enterTempEMail(tempEmail) + .sendEmail(); + String costOnCalcPage = cloudCalculatorPage.getTotalCost(); + + tempEmailPage.switchToNextTab(); + String costOnEmailPage = tempEmailPage.getCostFromEmail(); + + Assert.assertTrue(costOnCalcPage.contains(costOnEmailPage), "Total Cost from email doesn't match the one from the Calculator page"); + } +}