diff --git a/.github/sanityLilia.yml b/.github/sanityLilia.yml new file mode 100644 index 0000000..4d25248 --- /dev/null +++ b/.github/sanityLilia.yml @@ -0,0 +1,63 @@ +name: 🤖CI run Test Suite Execution🧪 +run-name: ${{github.actor}}👨🏻‍🔬 ran SanityTest in ${{github.ref_name}} + +#* El RUN de Pipeline para Sanity Test para verificación de archivos de prueba, tiene que usarse con su branch de tarea. +on: [workflow_dispatch] + push: + branches: ['test/GX3-3208/pdp-visualizar-detalles-del-item-producto'] + +jobs: + SanityTest: + name: Sanity Test + runs-on: ubuntu-latest + + steps: + - name: 💻Checkout + uses: actions/checkout@v4 + + - name: 💿Set up JAVA 20 with Maven + uses: actions/setup-java@v4 + with: + java-version: '20' + distribution: 'temurin' + cache: maven + + - name: 🧬Install All Dependencies with Maven + run: mvn -B package --file pom.xml + + - name: 🧪Run Selenium tests + run: mvn clean verify -D it.test=LiliaProductDetailTest -D headless=true + + - name: 📊Upload Artifact Maven Report + if: always() + uses: actions/upload-artifact@v4 + with: + name: regression-selenium-report + path: target/site/allure-maven-plugin + retention-days: 15 + + - name: ✅Import Test Results to Xray + if: always() + uses: mikepenz/xray-action@v2 + with: #todo: OPCIONES PARA IMPORTAR LOS RESULTADOS DE PRUEBA A JIRA XRAY: + username: ${{secrets.XRAY_CLIENT_ID}} + password: ${{secrets.XRAY_CLIENT_SECRET}} + testFormat: 'junit' #OPCIONES PARA CAMBIAR: 'junit' (para xml) o 'cucumber' (para json) + testPaths: 'target/failsafe-reports/TEST-*.xml' + testExecKey: 'GX3-3212' #? EDITAR AQUÍ EL TEST EXECUTION A IMPORTAR LAS PRUEBAS. + projectKey: 'GX3' #? EDITAR EN CASO DE TRABAJAR CON OTRO PROYECTO. + + Ari-Slack-Notification: + needs: [SanityTest] + if: always() + runs-on: ubuntu-latest + steps: + - name: 🔔Slack Notification of Done + if: env.SLACK_WEBHOOK != '' #? Corre este paso si la variable de entorno está definida + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_USERNAME: Ari✨ + SLACK_MESSAGE: ':test_tube: SELENIUM-JAVA (SwagLabs): SANITY TEST IMPORTED TO JIRA :rocket:' + SLACK_COLOR: ${{ job.status }} + SLACK_ICON: https://image.cdn2.seaart.ai/2023-12-06/clo9g0h4msbc73ac2sog/99e1abc36f32945cd4bacf5ee7448e96194545f7_high.webp diff --git a/coverage/in-sprint/S41/GX3-3208.md b/coverage/in-sprint/S41/GX3-3208.md new file mode 100644 index 0000000..7f6ad88 --- /dev/null +++ b/coverage/in-sprint/S41/GX3-3208.md @@ -0,0 +1,47 @@ +# ⚡️[Automation] SwagLabs | PDP | Visualizar Detalles del Item (Producto) + +[GX3-3208](https://upexgalaxy38.atlassian.net/browse/GX3-3208) Created: 22/4/24 Updated: 22/4/24 + +**COMO** Usuario de la página Web. [https://www.saucedemo.com/](https://www.saucedemo.com/ "smart-link") + +**QUIERO** Visualizar en el PDP: + +* Visualizar etiqueta con nombre del producto. +* Visualizar descripción del producto. +* Visualizar imagen del producto. +* Indicar precio del producto. +* Visualizar el Botón para Agregar el Producto al SCP o Removerlo +* Visualizar el Botón “Back to Products” para regresar + +**PARA** Conocer mas sobre el producto. + +``` +Feature: Product Detail Page + + Background: + Given: el usuario esta LOGEADO. + And: se situa en el PLP. + + Scenario: usuario ingresa en los Detalles de un producto sin añadir. + When: usuario seleciona cualquier producto (click en la imagen o nombre). + Then: se visualiza: + la etiqueta con nombre del producto. + la descripción del producto. + la imagen del producto. + el precio del producto. + el Botón "Back to Products" + el Botón "Add to Cart" + // Para más información, ver el MOCKUP + + Scenario: usuario ingresa en los Detalles de un producto añadido al SCP. + Given: el producto debe haber sido añadido al SCP (de cualquier modo) + When: usuario seleciona cualquier producto (click en la imagen o nombre). + Then: se visualiza: + la etiqueta con nombre del producto. + la descripción del producto. + la imagen del producto. + el precio del producto. + el Botón "Back to Products" + el Botón "Remove" + // Para más información, ver el MOCKUP<> +``` \ No newline at end of file diff --git a/src/test/java/e2e/pages/Lilia/LoginPage.java b/src/test/java/e2e/pages/Lilia/LoginPage.java new file mode 100644 index 0000000..f5445fa --- /dev/null +++ b/src/test/java/e2e/pages/Lilia/LoginPage.java @@ -0,0 +1,51 @@ +package e2e.pages.Lilia; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import com.google.common.base.Supplier; + +import e2e.utils.Action; +import e2e.utils.Locator; + +// Tech Debt:GX3-3180 = https://upexgalaxy38.atlassian.net/browse/GX3-3180 +public class LoginPage { + + WebDriver web; + Locator get; + Action Do; + private Supplier usernameInput; + private Supplier passwordInput; + private Supplier loginSubmitButton; + + public LoginPage(WebDriver driver, Locator locator, Action action) { + this.web = driver; + this.get = locator; + this.Do = action; + + this.usernameInput = () -> this.get.ByTestId("username"); + this.passwordInput = () -> this.get.ByTestId("password"); + this.loginSubmitButton = () -> this.get.ByTestId("login-button"); + + } + + public void enterUsername(String value) { + this.Do.enterValue(this.usernameInput.get(), value); + } + + public void enterPassword(String value) { + this.Do.enterValue(this.passwordInput.get(), value); + } + + public void submitLogin() { + this.Do.click(this.loginSubmitButton.get()); + + } + + public void Login() { + this.enterUsername("standard_user"); + this.enterPassword("secret_sauce"); + this.submitLogin(); + } + +} \ No newline at end of file diff --git a/src/test/java/e2e/pages/Lilia/ProductDetailPage.java b/src/test/java/e2e/pages/Lilia/ProductDetailPage.java new file mode 100644 index 0000000..35ca057 --- /dev/null +++ b/src/test/java/e2e/pages/Lilia/ProductDetailPage.java @@ -0,0 +1,64 @@ +package e2e.pages.Lilia; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import com.google.common.base.Supplier; + +import e2e.utils.Action; +import e2e.utils.Locator; + +public class ProductDetailPage { + WebDriver web; + Locator get; + Action Do; + private Supplier productDetailName; + private Supplier productDetailPrice; + private Supplier productDetailDescription; + private Supplier productDetailImg; + private Supplier backToProductsButton; + private Supplier addToCartButton; + + public ProductDetailPage(WebDriver driver, Locator locator, Action action) { + this.web = driver; + this.get = locator; + this.Do = action; + + this.productDetailName = () -> this.get.Selector("div[data-test=inventory-item-name]"); + this.productDetailImg = () -> this.get.ByClass("inventory_details_img"); + this.productDetailPrice = () -> this.get.Selector("div[data-test=inventory-item-price]"); + this.productDetailDescription = () -> this.get.Selector("div[data-test=inventory-item-desc]"); + this.backToProductsButton = () -> this.get.Selector("button[data-test=back-to-products]"); + this.addToCartButton = () -> this.get.Selector("button[data-test=add-to-cart]"); + } + + public String getProductDetailName() { + String title = this.productDetailName.get().getText(); + return title; + } + + public String getProductDetailPrice() { + String price = this.productDetailPrice.get().getText(); + return price; + } + + public String getProductDetailDescription() { + String description = this.productDetailDescription.get().getText(); + return description; + } + + public WebElement getProductDetailImg() { + return this.productDetailImg.get(); + + } + + public WebElement getBackToProductsButton() { + return this.backToProductsButton.get(); + } + + public WebElement getAddToCartButton() { + + return this.addToCartButton.get(); + } + +} \ No newline at end of file diff --git a/src/test/java/e2e/pages/Lilia/ProductListPage.java b/src/test/java/e2e/pages/Lilia/ProductListPage.java new file mode 100644 index 0000000..e018244 --- /dev/null +++ b/src/test/java/e2e/pages/Lilia/ProductListPage.java @@ -0,0 +1,76 @@ +package e2e.pages.Lilia; + +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import e2e.utils.Action; +import e2e.utils.Locator; + +// Tech Debt:GX3-3180 = https://upexgalaxy38.atlassian.net/browse/GX3-3208 + +public class ProductListPage { + WebDriver web; + Locator get; + Action Do; + + private Supplier> productTitles; + private Supplier> productPrices; + private Supplier> productDescriptions; + private String selectedName; + private String selectedPrice; + private String selectedDescription; + + public ProductListPage(WebDriver driver, Locator locator, Action action) { + this.web = driver; + this.get = locator; + this.Do = action; + + // Selectores + this.productTitles = () -> this.get.Selectors("div[data-test=inventory-item-name]"); + this.productPrices = () -> this.get.Selectors("div[data-test=inventory-item-price]"); + this.productDescriptions = () -> this.get.Selectors("div[data-test=inventory-item-desc]"); + + } + + public Integer randomNumber(Integer number) { + Random rand = new Random(); + int randomIndex = rand.nextInt(number); + return randomIndex; + } + + public void clickOnRandomProductTitle() { + List productElements = this.productTitles.get(); + int productsNamesIndex = productElements.size(); + int randomProductIndex = randomNumber(productsNamesIndex); + + // Store the selected product data before clicking on the product title + String selectedName = productElements.get(randomProductIndex).getText(); + String selectedPrice = this.productPrices.get().get(randomProductIndex).getText(); + String selectedDescription = this.productDescriptions.get().get(randomProductIndex).getText(); + // Accede al elemento en el índice aleatorio y haz clic en él + productElements.get(randomProductIndex).click(); + + // Actualiza los datos del producto seleccionado + this.selectedName = selectedName; + this.selectedPrice = selectedPrice; + this.selectedDescription = selectedDescription; + + } + + public String getselectedName() { + return this.selectedName; + } + + public String getSelectedPrice() { + return this.selectedPrice; + } + + public String getSelectedDescription() { + return this.selectedDescription; + } + +} \ No newline at end of file diff --git a/src/test/java/e2e/pages/Lilia/ShoppigCartPage.java b/src/test/java/e2e/pages/Lilia/ShoppigCartPage.java new file mode 100644 index 0000000..06055d5 --- /dev/null +++ b/src/test/java/e2e/pages/Lilia/ShoppigCartPage.java @@ -0,0 +1,64 @@ +package e2e.pages.Lilia; + +import java.util.function.Supplier; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import e2e.utils.Action; +import e2e.utils.Locator; + +public class ShoppigCartPage { + WebDriver web; + Locator get; + Action Do; + private Supplier removeButton; + private Supplier continueShoppingButton; + private Supplier shoppingCartIcon; + private Supplier addToCartButton; + private Supplier productName; + private Supplier productPrice; + private Supplier productDescription; + + public ShoppigCartPage(WebDriver driver, Locator locator, Action action) { + this.web = driver; + this.get = locator; + this.Do = action; + + this.removeButton = () -> this.get.Selector("button[data-test^='remove']"); + this.continueShoppingButton = () -> this.get.Selector("button[data-test=continue-shopping]"); + this.shoppingCartIcon = () -> this.get.Selector("a[data-test=shopping-cart-link]"); + this.addToCartButton = () -> this.get.Selector("button[data-test=add-to-cart]"); + this.productName = () -> this.get.Selector("div[data-test=inventory-item-name]"); + this.productPrice = () -> this.get.Selector("div[data-test=inventory-item-price]"); + this.productDescription = () -> this.get.Selector("div[data-test=inventory-item-desc]"); + } + + public void clickAddToCartButton() { + this.Do.click(this.addToCartButton.get()); + } + + public void clickShoppingCartIcon() { + this.Do.click(this.shoppingCartIcon.get()); + } + + public String getProductName() { + return this.productName.get().getText(); + } + + public String getProductPrice() { + return this.productPrice.get().getText(); + } + + public String getProductDescription() { + return this.productDescription.get().getText(); + } + + public WebElement getRemoveButton() { + return this.removeButton.get(); + } + + public WebElement getContinueShopping() { + return this.continueShoppingButton.get(); + } +} diff --git a/src/test/java/e2e/steps/PDP/LiliaProductDetailTest.java b/src/test/java/e2e/steps/PDP/LiliaProductDetailTest.java new file mode 100644 index 0000000..11d5af6 --- /dev/null +++ b/src/test/java/e2e/steps/PDP/LiliaProductDetailTest.java @@ -0,0 +1,104 @@ +package e2e.steps.PDP; + +import org.junit.jupiter.api.*; +import org.openqa.selenium.WebElement; + +import e2e.fixtures.TestBase; +import e2e.pages.Lilia.LoginPage; +import e2e.pages.Lilia.ProductDetailPage; +import e2e.pages.Lilia.ProductListPage; +import e2e.pages.Lilia.ShoppigCartPage; +import io.qameta.allure.*; +import static io.qameta.allure.SeverityLevel.*; + +import java.io.IOException; + +// Tech Debt:GX3-3208 = https://upexgalaxy38.atlassian.net/browse/GX3-3208 +public class LiliaProductDetailTest extends TestBase { + @Epic("PDP") + @Feature("") + @Story("GX3-3208: SwagLabs | PDP | Visualizar Detalles del Item") + @BeforeEach + public void precondition() { + + LoginPage loginPage = new LoginPage(web, get, Do); + web.get(BASE_URL); + loginPage.Login(); + then.shouldContain(web.getCurrentUrl(), "inventory.html"); + } + + @Test + @Severity(BLOCKER) + @DisplayName("TC1: Validate clicking on the product's Details without adding to the shopping cart") + @Description("Validate clicking on the product's Details") + + public void productDetailTest(TestInfo testInfo) throws InterruptedException, IOException { + ProductListPage productListPage = new ProductListPage(web, get, Do); + ProductDetailPage productDetailPage = new ProductDetailPage(web, get, Do); + + Allure.step("Step 1: Click on random product", (step) -> { + productListPage.clickOnRandomProductTitle(); + }); + + String productName = productListPage.getselectedName(); + String productPrice = productListPage.getSelectedPrice(); + String productDesc = productListPage.getSelectedDescription(); + + String productDetailName = productDetailPage.getProductDetailName(); + String productDetailPrice = productDetailPage.getProductDetailPrice(); + WebElement productDetailImg = productDetailPage.getProductDetailImg(); + String productDetailDesc = productDetailPage.getProductDetailDescription(); + + Allure.step("Expected result: Random product is selected successfully", (step) -> { + then.shouldContain(web.getCurrentUrl(), "inventory-item.html?id="); + then.shouldBeEqual(productDetailName, productName); + then.shouldBeEqual(productDetailPrice, productPrice); + then.shouldBeEqual(productDetailDesc, productDesc); + then.shouldBeVisible(productDetailImg); + then.shouldBeVisible(productDetailPage.getAddToCartButton()); + then.shouldBeVisible(productDetailPage.getBackToProductsButton()); + Do.screenshot(testInfo); + + }); + + } + + @Test + @Severity(BLOCKER) + @DisplayName("TC2: Validate product's details added to the SCP") + @Description("Validate product's details from the shopping cart page") + public void productShoppingCartTest(TestInfo testInfo) throws InterruptedException, IOException { + ProductListPage productListPage = new ProductListPage(web, get, Do); + ShoppigCartPage shoppigCartPage = new ShoppigCartPage(web, get, Do); + + Allure.step("Step 1: Click on random product", (step) -> { + productListPage.clickOnRandomProductTitle(); + }); + + String productName = productListPage.getselectedName(); + String productPrice = productListPage.getSelectedPrice(); + String productDesc = productListPage.getSelectedDescription(); + Allure.step("Step 2: Add product to shopping cart", (step) -> { + shoppigCartPage.clickAddToCartButton(); + }); + + Allure.step("Step 3: click on shopping cart icon", () -> { + shoppigCartPage.clickShoppingCartIcon(); + }); + String productShoppingCartName = shoppigCartPage.getProductName(); + String productShoppingCartDescription = shoppigCartPage.getProductDescription(); + String productShoppingCartPrice = shoppigCartPage.getProductPrice(); + + Allure.step("Expected result: Verify product's details in the shopping cart", (step) -> { + then.shouldBeEqual(productShoppingCartName, productName); + then.shouldBeEqual(productShoppingCartDescription, productDesc); + then.shouldBeEqual(productShoppingCartPrice, productPrice); + then.shouldBeVisible(shoppigCartPage.getRemoveButton()); + then.shouldBeVisible(shoppigCartPage.getContinueShopping()); + Do.screenshot(testInfo); + + }); + + } + +}