diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..35471d4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + target-branch: main + open-pull-requests-limit: 20 + schedule: + interval: "weekly" + timezone: "Asia/Calcutta" + groups: + dependencies: + dependency-type: 'production' + + - package-ecosystem: "github-actions" + directory: "/" + target-branch: main + open-pull-requests-limit: 20 + schedule: + interval: "weekly" + timezone: "Asia/Calcutta" + groups: + dependencies: + dependency-type: 'production' diff --git a/.github/workflows/disabled_maven.yml b/.github/workflows/disabled_maven.yml new file mode 100644 index 0000000..f7586dd --- /dev/null +++ b/.github/workflows/disabled_maven.yml @@ -0,0 +1,79 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: + - main + - issue-* + + pull_request: + branches: + - main + - issue-* + +permissions: + statuses: write + checks: write + contents: write + pull-requests: write + +jobs: + build: + name: Build and Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Install Java and Maven + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'adopt' + cache: maven + + - name: Checkout Practice Software Testing repo + uses: actions/checkout@v4 + with: + repository: testsmith-io/practice-software-testing + path: practice-repo + + - name: Start Practice Software Testing with Docker Compose + working-directory: practice-repo + run: docker compose up -d + + - name: Install Chrome + uses: browser-actions/setup-chrome@latest + + - name: Build Project and run tests + run: mvn clean install + + - name: Upload screenshots + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-screenshots + path: screenshots + + - name: Test Report + uses: dorny/test-reporter@v2 + if: success() || failure() + with: + name: Test Results + path: ${{ github.workspace }}/target/surefire-reports/TEST-TestSuite.xml + reporter: java-junit + java-version: 17 \ No newline at end of file diff --git a/.gitignore b/.gitignore index af27779..73f7c40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ target/ .idea/ +/screenshots/ ### VS Code ### .vscode/ diff --git a/UI/package-lock.json b/UI/package-lock.json new file mode 100644 index 0000000..4ca926f --- /dev/null +++ b/UI/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "app", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/pom.xml b/pom.xml index 87d60f1..9ecdc5b 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,8 @@ 3.13.0 3.5.0 UTF-8 + testng.xml + -Dfile.encoding=UTF-8 -Xdebug -Xnoagent @@ -76,6 +78,10 @@ false + + ${suite-xml} + + ${argLine} diff --git a/src/test/java/io/github/mfaisalkhatri/pages/HomePage.java b/src/test/java/io/github/mfaisalkhatri/pages/HomePage.java new file mode 100644 index 0000000..2020009 --- /dev/null +++ b/src/test/java/io/github/mfaisalkhatri/pages/HomePage.java @@ -0,0 +1,25 @@ +package io.github.mfaisalkhatri.pages; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +public class HomePage { + + private final WebDriver driver; + + public HomePage(WebDriver driver) { + this.driver=driver; + } + + public LoginPage navigateToLoginPage() { + signInLink ().click (); + return new LoginPage (driver); + + } + private WebElement signInLink() { + return this.driver.findElement (By.linkText ("Sign in")); + } + + +} diff --git a/src/test/java/io/github/mfaisalkhatri/pages/LoginPage.java b/src/test/java/io/github/mfaisalkhatri/pages/LoginPage.java new file mode 100644 index 0000000..977374b --- /dev/null +++ b/src/test/java/io/github/mfaisalkhatri/pages/LoginPage.java @@ -0,0 +1,24 @@ +package io.github.mfaisalkhatri.pages; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +public class LoginPage { + + private WebDriver driver; + + public LoginPage (WebDriver driver) { + this.driver = driver; + } + + private WebElement registerYourAccountLink () { + return this.driver.findElement (By.linkText ("Register your account")); + } + + public RegistrationPage navigateToRegistrationPage () { + registerYourAccountLink ().click (); + return new RegistrationPage (driver); + } + +} diff --git a/src/test/java/io/github/mfaisalkhatri/pages/RegistrationPage.java b/src/test/java/io/github/mfaisalkhatri/pages/RegistrationPage.java index da4233e..2340321 100644 --- a/src/test/java/io/github/mfaisalkhatri/pages/RegistrationPage.java +++ b/src/test/java/io/github/mfaisalkhatri/pages/RegistrationPage.java @@ -1,17 +1,27 @@ package io.github.mfaisalkhatri.pages; +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + import io.github.mfaisalkhatri.data.RegistrationData; 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.Select; +import org.openqa.selenium.support.ui.WebDriverWait; public class RegistrationPage { private final WebDriver driver; + private final WebDriverWait wait; + public RegistrationPage (final WebDriver driver) { + this.driver = driver; + this.wait = new WebDriverWait (driver, Duration.ofSeconds (30)); } public void fillRegistrationForm (final RegistrationData registrationData) { @@ -19,7 +29,7 @@ public void fillRegistrationForm (final RegistrationData registrationData) { firstNameField ().sendKeys (registrationData.getFirstName ()); lastNameField ().clear (); lastNameField ().sendKeys (registrationData.getLastName ()); - dobField ().sendKeys (registrationData.getDob ()); + dobField ().sendKeys (dateOfBirth (registrationData.getDob ())); streetField ().clear (); streetField ().sendKeys (registrationData.getStreet ()); postalCodeField ().clear (); @@ -39,12 +49,12 @@ public void fillRegistrationForm (final RegistrationData registrationData) { } public String pageHeader () { - return this.driver.findElement (By.cssSelector ("app-register h3")) + return wait.until (ExpectedConditions.visibilityOfElementLocated (By.cssSelector ("app-register h3"))) .getText (); } public String passwordAlertMessage () { - return this.driver.findElement (By.cssSelector (".alert-danger div")) + return wait.until (ExpectedConditions.visibilityOfElementLocated (By.cssSelector (".alert-danger div"))) .getText (); } @@ -99,4 +109,13 @@ private WebElement stateField () { private WebElement streetField () { return this.driver.findElement (By.id ("street")); } + + private String dateOfBirth (String jsonDate) { + + DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern ("dd/MM/yyyy"); + LocalDate date = LocalDate.parse (jsonDate, inputFormat); + + DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern ("MM/dd/yyyy"); + return date.format (outputFormat); + } } diff --git a/src/test/java/io/github/mfaisalkhatri/test/BaseTest.java b/src/test/java/io/github/mfaisalkhatri/test/BaseTest.java index 6cffe1e..3d13aee 100644 --- a/src/test/java/io/github/mfaisalkhatri/test/BaseTest.java +++ b/src/test/java/io/github/mfaisalkhatri/test/BaseTest.java @@ -2,21 +2,28 @@ import java.time.Duration; +import io.github.mfaisalkhatri.utils.WebDriverProvider; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; -public class BaseTest { +public class BaseTest implements WebDriverProvider { protected WebDriver driver; + @Override + public WebDriver getDriver () { + return driver; + } + @BeforeClass public void setup () { - this.driver = new ChromeDriver (); - this.driver.manage () - .window () - .maximize (); + ChromeOptions chromeOptions = new ChromeOptions (); + chromeOptions.addArguments ("--headless=new","--no-sandbox", "--window-size=1920,1080"); + + this.driver = new ChromeDriver (chromeOptions); this.driver.manage () .timeouts () .implicitlyWait (Duration.ofSeconds (30)); @@ -24,6 +31,8 @@ public void setup () { @AfterClass public void tearDown () { - this.driver.quit (); + if (driver != null) { + this.driver.quit (); + } } } diff --git a/src/test/java/io/github/mfaisalkhatri/test/JsonDataProviderTest.java b/src/test/java/io/github/mfaisalkhatri/test/JsonDataProviderTest.java index 8e55872..e7185e2 100644 --- a/src/test/java/io/github/mfaisalkhatri/test/JsonDataProviderTest.java +++ b/src/test/java/io/github/mfaisalkhatri/test/JsonDataProviderTest.java @@ -2,11 +2,21 @@ import static org.testng.Assert.assertEquals; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Iterator; import io.github.mfaisalkhatri.data.RegistrationData; import io.github.mfaisalkhatri.data.RegistrationDataBuilder; +import io.github.mfaisalkhatri.pages.HomePage; +import io.github.mfaisalkhatri.pages.LoginPage; import io.github.mfaisalkhatri.pages.RegistrationPage; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -21,12 +31,27 @@ public Iterator getValidRegistrationData () { @Test (dataProvider = "getValidRegistrationData") public void testRegistrationPasswordAlert (final RegistrationData registrationData) { - final RegistrationPage registrationPage = new RegistrationPage (this.driver); + //this.driver.get ("http://localhost:4200/"); this.driver.get ("https://practicesoftwaretesting.com/auth/register"); + HomePage homePage = new HomePage (driver); + LoginPage loginPage = homePage.navigateToLoginPage (); + RegistrationPage registrationPage = loginPage.navigateToRegistrationPage (); + + String timestamp = new SimpleDateFormat ("yyyyMMdd_HHmmss_SSS").format (new Date ()); + + File screenshot = ((TakesScreenshot) driver).getScreenshotAs (OutputType.FILE); + String filename = timestamp + ".png"; + try { + Files.createDirectories (Paths.get ("screenshots")); + Files.copy (screenshot.toPath (), Paths.get ("screenshots", filename)); + } catch (IOException e) { + throw new RuntimeException (e); + } + assertEquals (registrationPage.pageHeader (), "Customer registration"); - registrationPage.fillRegistrationForm (registrationData); + registrationPage.fillRegistrationForm (registrationData); assertEquals (registrationPage.passwordAlertMessage (), "The given password has appeared in a data leak. Please choose a different password."); } diff --git a/src/test/java/io/github/mfaisalkhatri/utils/ScreenshotListener.java b/src/test/java/io/github/mfaisalkhatri/utils/ScreenshotListener.java new file mode 100644 index 0000000..b16ce3c --- /dev/null +++ b/src/test/java/io/github/mfaisalkhatri/utils/ScreenshotListener.java @@ -0,0 +1,36 @@ +package io.github.mfaisalkhatri.utils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; +import org.openqa.selenium.WebDriver; +import org.testng.ITestListener; +import org.testng.ITestResult; + +public class ScreenshotListener implements ITestListener { + @Override + public void onTestFailure (final ITestResult result) { + Object testClass = result.getInstance (); + WebDriver driver = ((WebDriverProvider) testClass).getDriver (); + String timestamp = new SimpleDateFormat ("yyyyMMdd_HHmmss_SSS").format (new Date ()); + + if (driver != null) { + String testName = result.getMethod () + .getMethodName (); + File screenshot = ((TakesScreenshot) driver).getScreenshotAs (OutputType.FILE); + String filename = timestamp + ".png"; + try { + Files.createDirectories (Paths.get ("screenshots")); + Files.copy (screenshot.toPath (), Paths.get ("screenshots", testName + "_" + filename)); + } catch (IOException e) { + throw new RuntimeException (e); + } + } + } +} diff --git a/src/test/java/io/github/mfaisalkhatri/utils/WebDriverProvider.java b/src/test/java/io/github/mfaisalkhatri/utils/WebDriverProvider.java new file mode 100644 index 0000000..9d1ed96 --- /dev/null +++ b/src/test/java/io/github/mfaisalkhatri/utils/WebDriverProvider.java @@ -0,0 +1,7 @@ +package io.github.mfaisalkhatri.utils; + +import org.openqa.selenium.WebDriver; + +public interface WebDriverProvider { + WebDriver getDriver (); +} \ No newline at end of file diff --git a/src/test/resources/testdata.json b/src/test/resources/testdata.json index 195a994..49beac3 100644 --- a/src/test/resources/testdata.json +++ b/src/test/resources/testdata.json @@ -3,7 +3,7 @@ { "firstName": "Jason", "lastName": "Langer", - "dob": "01/04/1987", + "dob": "17/05/1987", "street": "11/2, Fort Street", "postalCode": "113445", "city": "California", @@ -17,7 +17,7 @@ { "firstName": "Michael", "lastName": "Justin", - "dob": "23/07/1981", + "dob": "23/07/1985", "street": "21/4, Dallas Street", "postalCode": "12976", "city": "California", diff --git a/testng.xml b/testng.xml index a359927..40495cd 100644 --- a/testng.xml +++ b/testng.xml @@ -1,6 +1,9 @@ + + +