diff --git a/java-reporter-testng-selenide/README.md b/java-reporter-testng-selenide/README.md new file mode 100644 index 0000000..0276e71 --- /dev/null +++ b/java-reporter-testng-selenide/README.md @@ -0,0 +1,62 @@ +# Java reporter integration with TestNG + +## Overview + +This simple demo shows how Testomat.io Java reporter works in your project. + +## Installation + +1. Clone the repository + +```sh + git clone https://github.com/testomatio/examples.git + ``` +2. Change the directory + +```sh + cd java-reporter-testng +``` +3. Install dependencies with test skip + +```sh + mvn clean install -DskipTests +``` + + +## Configurations + +**By default, the library runs with properties default values except `testomatio.api.key` and `testomatio.listening`** + +![properties img](img/properties.png) + +Add your project API key to the `testomatio.properties` file ad `testomatio.api.key` + +## Configure TestNG Before Running + +Before running tests, make sure your TestNG suites are configured in the testng.xml file. +Runs test methods in parallel using 7 threads simultaneously. +```xml + + + + + + + + + + + + + +``` + +## Run + +Run tests with + +```bash + mvn test -Dtestomatio.api.key=tstmt_key #if you did not provide it in the `testomatio.properties` file +``` + +where `tstmt_key` is your Testomat.io key from a particular project. diff --git a/java-reporter-testng-selenide/pom.xml b/java-reporter-testng-selenide/pom.xml new file mode 100644 index 0000000..840e385 --- /dev/null +++ b/java-reporter-testng-selenide/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + io.testomat + java-reporter-testng-selenide + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + 7.16.1 + 7.11.0 + 2.29.1 + + + + + com.codeborne + selenide + ${selenide.version} + + + org.testng + testng + ${testng.version} + test + + + io.testomat + java-reporter-testng + 0.12.0 + + + org.assertj + assertj-core + 3.27.3 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + testng.xml + + + + + + + \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/config/Urls.java b/java-reporter-testng-selenide/src/main/java/io/testomat/config/Urls.java new file mode 100644 index 0000000..343be51 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/config/Urls.java @@ -0,0 +1,15 @@ +package io.testomat.config; + +public final class Urls { + + public static final String BASE_URL = "https://www.saucedemo.com/"; + public static final String INVENTORY_URL = BASE_URL + "inventory.html"; + private static final String INVENTORY_ITEM_PATTERN = BASE_URL + INVENTORY_URL + "?id=%s"; + + private Urls() { + } + + public static String inventoryItemUrl(int id) { + return String.format(INVENTORY_ITEM_PATTERN, id); + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/data/Users.java b/java-reporter-testng-selenide/src/main/java/io/testomat/data/Users.java new file mode 100644 index 0000000..8db86f7 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/data/Users.java @@ -0,0 +1,28 @@ +package io.testomat.data; + +public final class Users { + + public static final String PASSWORD = + "secret_sauce"; + + public static final String STANDARD_USER = + "standard_user"; + + public static final String LOCKED_USER = + "locked_out_user"; + + public static final String PROBLEM_USER = + "problem_user"; + + public static final String PERFORMANCE_USER = + "performance_glitch_user"; + + public static final String ERROR_USER = + "error_user"; + + public static final String VISUAL_USER = + "visual_user"; + + private Users() { + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/pages/CartPage.java b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/CartPage.java new file mode 100644 index 0000000..40fc2c5 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/CartPage.java @@ -0,0 +1,32 @@ +package io.testomat.pages; + +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; + +import static com.codeborne.selenide.CollectionCondition.sizeGreaterThan; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; + +public class CartPage { + + private final ElementsCollection cartItems = + $$(".cart_item"); + + private final SelenideElement cartLink = + $(".shopping_cart_link"); + + public CartPage verifyItemsExist() { + cartItems.shouldHave(sizeGreaterThan(0)); + + return this; + } + + public int getItemsCount() { + return cartItems.size(); + } + + public void cartLinkShouldVisible() { + cartLink.shouldBe(visible); + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/pages/InventoryPage.java b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/InventoryPage.java new file mode 100644 index 0000000..2e03567 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/InventoryPage.java @@ -0,0 +1,136 @@ +package io.testomat.pages; + +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; + +import java.util.List; + +import static com.codeborne.selenide.CollectionCondition.sizeGreaterThan; +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selenide.*; + +public class InventoryPage { + + private final SelenideElement title = + $(".title"); + + private final ElementsCollection inventoryItems = + $$(".inventory_item"); + + private final ElementsCollection itemNames = + $$(".inventory_item_name"); + + private final ElementsCollection itemPrices = + $$(".inventory_item_price"); + + private final SelenideElement cartButton = + $(".shopping_cart_link"); + + private final SelenideElement sortDropdown = + $(".product_sort_container"); + + private final ElementsCollection addToCartButtons = + $$("button[id^='add-to-cart']"); + + private final ElementsCollection removeButtons = + $$("button[id^='remove']"); + + private final SelenideElement burgerMenu = + $("#react-burger-menu-btn"); + + private final SelenideElement logoutLink = + $("#logout_sidebar_link"); + + private final ElementsCollection inventoryItemsImgs = + $$(".inventory_item_img img"); + + private final SelenideElement inventoryDetailsImgs = + $(".inventory_details_img img"); + + private final SelenideElement inventoryDetailsName = + $(".inventory_details_name"); + + private final SelenideElement inventoryList = + $(".inventory_list"); + + public InventoryPage verifyPageLoaded() { + title.shouldHave(text("Products")); + inventoryItems.shouldHave(sizeGreaterThan(0)); + + return this; + } + + public int getItemsCount() { + + return inventoryItems.size(); + } + + public List getItemNames() { + + return itemNames.texts(); + } + + public List getItemPrices() { + return itemPrices.texts(); + } + + public InventoryPage sortBy(String value) { + + sortDropdown.selectOptionByValue(value); + + return this; + } + + public InventoryPage addFirstItemToCart() { + addToCartButtons.first().click(); + + return this; + } + + public InventoryPage removeFirstItemFromCart() { + + removeButtons.first().click(); + + return this; + } + + public CartPage openCart() { + + cartButton.click(); + + return new CartPage(); + } + + public LoginPage logout() { + + burgerMenu.click(); + + logoutLink.shouldBe(visible).click(); + + return new LoginPage(); + } + + public ElementsCollection getInventoryItemsImgs() { + return inventoryItemsImgs; + } + + public SelenideElement getInventoryDetailsImgs() { + return inventoryDetailsImgs; + } + + public SelenideElement getInventoryDetailsName() { + return inventoryDetailsName; + } + + public void inventoryListShouldVisible() { + inventoryList.shouldBe(visible); + } + + public ElementsCollection getCartButtons() { + return addToCartButtons; + } + + public ElementsCollection getItemPriceElements() { + return itemPrices; + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/pages/LoginPage.java b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/LoginPage.java new file mode 100644 index 0000000..6d6475c --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/LoginPage.java @@ -0,0 +1,76 @@ +package io.testomat.pages; + +import com.codeborne.selenide.SelenideElement; +import io.testomat.config.Urls; + +import static com.codeborne.selenide.Condition.text; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.open; + +public class LoginPage { + + private final SelenideElement usernameInput = $("#user-name"); + private final SelenideElement passwordInput = $("#password"); + private final SelenideElement loginButton = $("#login-button"); + + private final SelenideElement errorMessage = $("h3[data-test='error']"); + + public LoginPage openPage() { + open(Urls.BASE_URL); + + return this; + } + + public LoginPage verifyErrorMessage(String text) { + errorMessage.shouldHave(text(text)); + + return this; + } + + public LoginPage enterUsername(String username) { + usernameInput + .shouldBe(visible) + .sendKeys(username); + + return this; + } + + public LoginPage enterPassword(String password) { + passwordInput + .shouldBe(visible) + .sendKeys(password); + + return this; + } + + public InventoryPage clickLogin() { + loginButton + .shouldBe(visible) + .click(); + + return new InventoryPage(); + } + + public LoginPage login() { + loginButton + .shouldBe(visible) + .click(); + + return this; + } + + public LoginPage clickLoginExpectingFailure() { + loginButton + .shouldBe(visible) + .click(); + + return this; + } + + public LoginPage verifyLoginButtonVisible() { + loginButton.shouldBe(visible); + + return this; + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/pages/ProductPage.java b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/ProductPage.java new file mode 100644 index 0000000..60136a8 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/pages/ProductPage.java @@ -0,0 +1,102 @@ +package io.testomat.pages; + +import com.codeborne.selenide.SelenideElement; + +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selenide.$; + +public class ProductPage { + + private final SelenideElement productName = + $(".inventory_details_name"); + + private final SelenideElement productDescription = + $(".inventory_details_desc"); + + private final SelenideElement productPrice = + $(".inventory_details_price"); + + private final SelenideElement productImage = + $(".inventory_details_img img"); + + private final SelenideElement addToCartButton = + $("button[id^='add-to-cart']"); + + private final SelenideElement removeButton = + $("button[id^='remove']"); + + private final SelenideElement backButton = + $("#back-to-products"); + + private final SelenideElement cartBadge = + $(".shopping_cart_badge"); + + private final SelenideElement productSortContainer = + $(".product_sort_container"); + + public ProductPage verifyPageLoaded() { + + productName.shouldBe(visible); + + productDescription.shouldBe(visible); + + productPrice.shouldBe(visible); + + productImage.shouldBe(visible); + + return this; + } + + public String getProductName() { + + return productName.getText(); + } + + public String getProductDescription() { + + return productDescription.getText(); + } + + public String getProductPrice() { + + return productPrice.getText(); + } + + public ProductPage addToCart() { + + addToCartButton + .shouldBe(enabled) + .click(); + + return this; + } + + public ProductPage removeFromCart() { + + removeButton + .shouldBe(enabled) + .click(); + + return this; + } + + public ProductPage verifyCartBadge(String count) { + cartBadge.shouldHave(text(count)); + + return this; + } + + public InventoryPage clickBackButton() { + backButton.click(); + + return new InventoryPage(); + } + + public SelenideElement getCartBadge() { + return cartBadge; + } + + public void productSortContainerShouldVisible() { + productSortContainer.shouldBe(visible); + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/steps/InventorySteps.java b/java-reporter-testng-selenide/src/main/java/io/testomat/steps/InventorySteps.java new file mode 100644 index 0000000..83695fd --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/steps/InventorySteps.java @@ -0,0 +1,13 @@ +package io.testomat.steps; + +import io.testomat.pages.ProductPage; + +public class InventorySteps { + + public String getCartBadgeAmount() { + return new ProductPage() + .getCartBadge() + .getText(); + } + +} diff --git a/java-reporter-testng-selenide/src/main/java/io/testomat/steps/LoginSteps.java b/java-reporter-testng-selenide/src/main/java/io/testomat/steps/LoginSteps.java new file mode 100644 index 0000000..923c33d --- /dev/null +++ b/java-reporter-testng-selenide/src/main/java/io/testomat/steps/LoginSteps.java @@ -0,0 +1,33 @@ +package io.testomat.steps; + +import com.codeborne.selenide.SelenideElement; +import io.testomat.data.Users; +import io.testomat.pages.InventoryPage; +import io.testomat.pages.LoginPage; + +public class LoginSteps { + + public static InventoryPage loginAsStandardUser() { + return new LoginPage() + .openPage() + .enterUsername("standard_user") + .enterPassword("secret_sauce") + .clickLogin() + .verifyPageLoaded(); + } + + public static InventoryPage loginAs(String username) { + + return new LoginPage() + .openPage() + .enterUsername(username) + .enterPassword(Users.PASSWORD) + .clickLogin() + .verifyPageLoaded(); + } + + public SelenideElement getInventoryDetailsName() { + return new InventoryPage().getInventoryDetailsName(); + } + +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/main/resources/testomatio.properties b/java-reporter-testng-selenide/src/main/resources/testomatio.properties new file mode 100644 index 0000000..23fd259 --- /dev/null +++ b/java-reporter-testng-selenide/src/main/resources/testomatio.properties @@ -0,0 +1,11 @@ +#Change to https://beta.testomat.io/ if you use it +testomatio.url=https://app.testomat.io/ + +#define the run title, or it will be default_run_title +testomatio.run.title=testng-example-run + +#Particular project api key, starts with "tstmt_" +testomatio.api.key= + +#enables/disables the reporting (remove value to disable) +testomatio.listening=true \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/test/java/base/BaseTest.java b/java-reporter-testng-selenide/src/test/java/base/BaseTest.java new file mode 100644 index 0000000..a8f6d10 --- /dev/null +++ b/java-reporter-testng-selenide/src/test/java/base/BaseTest.java @@ -0,0 +1,28 @@ +package base; + +import com.codeborne.selenide.Configuration; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import static com.codeborne.selenide.Selenide.closeWebDriver; + +public class BaseTest { + + @BeforeMethod + public void setup() { + Configuration.browser = "chrome"; + Configuration.browserSize = "1920x1080"; + Configuration.timeout = 10000; + Configuration.pageLoadTimeout = 60000; + Configuration.headless = false; + Configuration.screenshots = true; + Configuration.savePageSource = true; + Configuration.reopenBrowserOnFail = true; + Configuration.fastSetValue = true; + } + + @AfterMethod(alwaysRun = true) + public void tearDown() { + closeWebDriver(); + } +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/src/test/java/tests/InventoryTest.java b/java-reporter-testng-selenide/src/test/java/tests/InventoryTest.java new file mode 100644 index 0000000..8886841 --- /dev/null +++ b/java-reporter-testng-selenide/src/test/java/tests/InventoryTest.java @@ -0,0 +1,186 @@ +package tests; + +import static com.codeborne.selenide.Condition.empty; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.open; +import static com.codeborne.selenide.Selenide.refresh; +import static com.codeborne.selenide.Selenide.webdriver; +import static com.codeborne.selenide.WebDriverConditions.url; + +import base.BaseTest; +import io.testomat.config.Urls; +import io.testomat.steps.InventorySteps; +import java.util.Comparator; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.Test; +import io.testomat.pages.CartPage; +import io.testomat.pages.InventoryPage; +import io.testomat.pages.LoginPage; +import io.testomat.steps.LoginSteps; + +public class InventoryTest extends BaseTest { + + @Test + public void inventoryShouldBeLoaded() { + InventoryPage page = LoginSteps.loginAsStandardUser(); + Assert.assertTrue(page.getItemsCount() > 0); + } + + @Test + public void inventoryTitleShouldBeVisible() { + LoginSteps.loginAsStandardUser() + .verifyPageLoaded(); + } + + @Test + public void itemShouldBeAddedToCart() { + CartPage cartPage = + LoginSteps.loginAsStandardUser() + .addFirstItemToCart() + .openCart() + .verifyItemsExist(); + + Assert.assertEquals(cartPage.getItemsCount(), 1); + } + + @Test + public void itemShouldBeRemovedFromCart() { + InventoryPage page = + LoginSteps.loginAsStandardUser() + .addFirstItemToCart() + .removeFirstItemFromCart(); + + CartPage cartPage = page.openCart(); + + Assert.assertEquals(cartPage.getItemsCount(), 0); + } + + @Test + public void userShouldLogoutSuccessfully() { + LoginPage loginPage = + LoginSteps.loginAsStandardUser() + .logout(); + + loginPage.verifyLoginButtonVisible(); + } + + @Test + public void productsShouldBeSortedByNameAZ() { + InventoryPage page = + LoginSteps.loginAsStandardUser() + .sortBy("az"); + + List names = page.getItemNames(); + + List sorted = + names.stream() + .sorted() + .toList(); + + Assert.assertEquals(names, sorted); + } + + @Test + public void productsShouldBeSortedByNameZA() { + InventoryPage page = + LoginSteps.loginAsStandardUser() + .sortBy("za"); + + List names = page.getItemNames(); + + List sorted = + names.stream() + .sorted(Comparator.reverseOrder()) + .toList(); + + Assert.assertEquals(names, sorted); + } + + @Test + public void productsShouldBeSortedByPriceLowToHigh() { + InventoryPage page = + LoginSteps.loginAsStandardUser() + .sortBy("lohi"); + + List prices = + page.getItemPrices() + .stream() + .map(p -> Double.parseDouble( + p.replace("$", "") + )) + .toList(); + + List sorted = + prices.stream() + .sorted() + .toList(); + + Assert.assertEquals(prices, sorted); + } + + @Test + public void userShouldNotAccessInventoryWithoutLogin() { + open(Urls.INVENTORY_URL); + webdriver().shouldHave(url(Urls.BASE_URL)); + } + + @Test + public void lockedUserShouldNotLogin() { + new LoginPage() + .openPage() + .enterUsername("locked_out_user") + .enterPassword("secret_sauce") + .clickLoginExpectingFailure() + .verifyErrorMessage( + "Sorry, this user has been locked out." + ); + } + + @Test + public void cartShouldBeEmptyInitially() { + CartPage cartPage = + LoginSteps.loginAsStandardUser() + .openCart(); + + Assert.assertEquals(cartPage.getItemsCount(), 0); + } + + @Test + public void allProductImagesShouldBeVisible() { + new InventoryPage() + .getInventoryItemsImgs() + .forEach(img -> + img.shouldBe(visible)); + } + + @Test + public void addToCartButtonsShouldBeVisible() { + LoginSteps.loginAsStandardUser(); + new InventoryPage() + .getCartButtons() + .forEach(btn -> + btn.shouldBe(visible)); + } + + @Test + public void allPricesShouldBeVisible() { + LoginSteps.loginAsStandardUser(); + new InventoryPage() + .getItemPriceElements() + .forEach(price -> + price.shouldNotBe(empty) + ); + } + + @Test + public void cartShouldPersistAfterRefresh() { + LoginSteps.loginAsStandardUser() + .addFirstItemToCart(); + refresh(); + + Assert.assertEquals( + new InventorySteps().getCartBadgeAmount(), + "1"); + } +} diff --git a/java-reporter-testng-selenide/src/test/java/tests/LoginTest.java b/java-reporter-testng-selenide/src/test/java/tests/LoginTest.java new file mode 100644 index 0000000..7811169 --- /dev/null +++ b/java-reporter-testng-selenide/src/test/java/tests/LoginTest.java @@ -0,0 +1,129 @@ +package tests; + +import static com.codeborne.selenide.Condition.attributeMatching; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$$; +import static com.codeborne.selenide.Selenide.open; + +import base.BaseTest; +import io.testomat.config.Urls; +import io.testomat.data.Users; +import io.testomat.pages.CartPage; +import io.testomat.pages.InventoryPage; +import io.testomat.pages.ProductPage; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import io.testomat.pages.LoginPage; +import io.testomat.steps.LoginSteps; + +public class LoginTest extends BaseTest { + + @DataProvider(name = "validUsers") + public Object[][] validUsers() { + + return new Object[][]{ + {Users.STANDARD_USER}, + {Users.PROBLEM_USER}, + {Users.PERFORMANCE_USER}, + {Users.ERROR_USER}, + {Users.VISUAL_USER} + }; + } + + @Test(dataProvider = "validUsers") + public void validUsersShouldLogin(String username) { + + new LoginPage() + .openPage() + .enterUsername(username) + .enterPassword(Users.PASSWORD) + .clickLogin() + .verifyPageLoaded(); + } + + @Test + public void lockedUserShouldSeeError() { + new LoginPage() + .openPage() + .enterUsername(Users.LOCKED_USER) + .enterPassword(Users.PASSWORD) + .clickLoginExpectingFailure() + .verifyErrorMessage( + "Sorry, this user has been locked out." + ); + } + + @Test + public void performanceUserShouldLoginSuccessfully() { + long start = System.currentTimeMillis(); + + new LoginPage() + .openPage() + .enterUsername(Users.PERFORMANCE_USER) + .enterPassword(Users.PASSWORD) + .clickLogin() + .verifyPageLoaded(); + + long elapsed = System.currentTimeMillis() - start; + + Assert.assertTrue(elapsed > 2000); + } + + @Test + public void performanceUserInventoryShouldLoad() { + new LoginPage() + .openPage() + .enterUsername(Users.PERFORMANCE_USER) + .enterPassword(Users.PASSWORD) + .clickLogin() + .verifyPageLoaded(); + } + + @Test + public void problemUserShouldHaveBrokenImages() { + new LoginPage() + .openPage() + .enterUsername(Users.PROBLEM_USER) + .enterPassword(Users.PASSWORD) + .clickLogin(); + + $$("img") + .forEach(img -> + img.shouldHave(attributeMatching( + "src", + ".*sl-404.*" + )) + ); + } + + @Test + public void problemUserCanStillAddItemsToCart() { + + LoginSteps.loginAs(Users.PROBLEM_USER) + .addFirstItemToCart() + .openCart() + .verifyItemsExist(); + } + + @Test + public void errorUserShouldNavigateToProductPage() { + LoginSteps.loginAs(Users.ERROR_USER); + open(Urls.inventoryItemUrl(4)); + new LoginSteps().getInventoryDetailsName().shouldBe(visible); + } + + @Test + public void visualUserShouldOpenInventoryPage() { + LoginSteps.loginAs(Users.VISUAL_USER).verifyPageLoaded(); + } + + @Test + public void visualUserShouldSeeMainElements() { + LoginSteps.loginAs(Users.VISUAL_USER); + + new InventoryPage().inventoryListShouldVisible(); + new CartPage().cartLinkShouldVisible(); + new ProductPage().productSortContainerShouldVisible(); + } +} diff --git a/java-reporter-testng-selenide/src/test/java/tests/ProductDetailsTest.java b/java-reporter-testng-selenide/src/test/java/tests/ProductDetailsTest.java new file mode 100644 index 0000000..013ecc9 --- /dev/null +++ b/java-reporter-testng-selenide/src/test/java/tests/ProductDetailsTest.java @@ -0,0 +1,163 @@ +package tests; + +import base.BaseTest; +import io.testomat.config.Urls; +import io.testomat.pages.InventoryPage; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import io.testomat.pages.LoginPage; +import io.testomat.pages.ProductPage; + +import static com.codeborne.selenide.Condition.attributeMatching; +import static com.codeborne.selenide.Selenide.open; +import static com.codeborne.selenide.Selenide.refresh; +import static com.codeborne.selenide.Selenide.webdriver; +import static com.codeborne.selenide.WebDriverConditions.url; + +public class ProductDetailsTest extends BaseTest { + + @BeforeMethod + public void login() { + new LoginPage() + .openPage() + .enterUsername("standard_user") + .enterPassword("secret_sauce") + .clickLogin(); + } + + private ProductPage openProductPage() { + open(Urls.inventoryItemUrl(7)); + + return new ProductPage() + .verifyPageLoaded(); + } + + @Test + public void productPageShouldBeOpened() { + openProductPage(); + } + + @Test + public void productNameShouldBeVisible() { + ProductPage page = + openProductPage(); + + Assert.assertFalse( + page.getProductName().isBlank() + ); + } + + @Test + public void productDescriptionShouldBeVisible() { + ProductPage page = + openProductPage(); + + Assert.assertFalse( + page.getProductDescription().isBlank() + ); + } + + @Test + public void productPriceShouldBeVisible() { + ProductPage page = + openProductPage(); + + Assert.assertTrue( + page.getProductPrice().contains("$") + ); + } + + @Test + public void productImageShouldBeVisible() { + openProductPage(); + } + + @Test + public void itemShouldBeAddedToCart() { + openProductPage() + .addToCart() + .verifyCartBadge("1"); + } + + @Test + public void itemShouldBeRemovedFromCart() { + openProductPage() + .addToCart() + .removeFromCart(); + } + + @Test + public void backButtonShouldReturnToInventory() { + openProductPage() + .clickBackButton() + .verifyPageLoaded(); + } + + @Test + public void cartBadgeShouldIncreaseAfterAdd() { + openProductPage() + .addToCart() + .verifyCartBadge("1"); + } + + @Test + public void addToCartButtonShouldChangeToRemove() { + openProductPage() + .addToCart(); + } + + @Test + public void pageShouldBeRefreshSafe() { + ProductPage page = + openProductPage(); + + page.addToCart(); + refresh(); + + page.verifyCartBadge("1"); + } + + @Test + public void userShouldNotAccessProductPageWithoutLogin() { + open(Urls.inventoryItemUrl(3)); + webdriver().shouldHave( + url(Urls.BASE_URL) + ); + } + + @Test + public void invalidProductIdShouldNotCrashApplication() { + open(Urls.inventoryItemUrl(999)); + } + + @Test + public void correctProductShouldBeDisplayed() { + ProductPage page = + openProductPage(); + + Assert.assertEquals( + page.getProductName(), + "Sauce Labs Backpack" + ); + } + + @Test + public void imageShouldContainSrcAttribute() { + new InventoryPage() + .getInventoryDetailsImgs() + .shouldHave(attributeMatching("src", ".*")); + } + + @Test + public void addRemoveAddFlowShouldWork() { + ProductPage page = + openProductPage(); + + page.addToCart() + .removeFromCart() + .addToCart() + .verifyCartBadge("1"); + } + +} \ No newline at end of file diff --git a/java-reporter-testng-selenide/testng.xml b/java-reporter-testng-selenide/testng.xml new file mode 100644 index 0000000..f8d15cc --- /dev/null +++ b/java-reporter-testng-selenide/testng.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file