diff --git a/serenity-cucumber/README.md b/serenity-cucumber/README.md new file mode 100644 index 0000000..fdcf8fe --- /dev/null +++ b/serenity-cucumber/README.md @@ -0,0 +1,54 @@ +# browserstack-selenium-load-testing-sample + +![BrowserStack Logo](https://d98b8t1nnulk5.cloudfront.net/production/images/layout/logo-header.png?1469004780) + +## Getting Started + +### Run Sample Build + +1. **Clone the repository** + + ```sh + git clone https://github.com/browserstack/browserstack-selenium-load-testing-sample.git + cd browserstack-selenium-load-testing-sample + cd serenity-cucumber + ``` + +2. **Install Maven dependencies** + + ```sh + mvn compile + ``` + +3. **Install BrowserStack CLI** + + Download the appropriate BrowserStack CLI binary based on your operating system: + + - **macOS x86** + [browserstack-cli-macOS-x86](https://load-api.browserstack.com/api/v1/binary?os=macos&arch=x64) + + - **macOS ARM** + [browserstack-cli-macOS-arm](https://load-api.browserstack.com/api/v1/binary?os=macos&arch=arm64) + + - **Windows x86** + [browserstack-cli-windows](https://load-api.browserstack.com/api/v1/binary?os=win&arch=x64) + + - **Linux x86** + [browserstack-cli-linux-x86](https://load-api.browserstack.com/api/v1/binary?os=linux&arch=arm64) + + - **Linux ARM** + [browserstack-cli-linux-arm](https://load-api.browserstack.com/api/v1/binary?os=linux&arch=x64) + + > Place the downloaded `browserstack-cli` binary in the root of your project. + +4. **Run tests using BrowserStack CLI** + + ```sh + ./browserstack-cli load run + ``` + +5. **View Test Results** + + Visit the [BrowserStack Load-Testing Dashboard](https://load.browserstack.com/projects) to monitor and analyze your test runs. + +--- diff --git a/serenity-cucumber/browserstack-load.yml b/serenity-cucumber/browserstack-load.yml new file mode 100644 index 0000000..6810ab2 --- /dev/null +++ b/serenity-cucumber/browserstack-load.yml @@ -0,0 +1,44 @@ +# ============================= +# Set BrowserStack Credentials +# ============================= +# Add your BrowserStack userName and accessKey here or set BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY as env variables. +userName: BROWSERSTACK_USERNAME +accessKey: BROWSERSTACK_ACCESS_KEY + +# ====================== +# BrowserStack Reporting +# ====================== +# The following parameters are used to set up reporting on BrowserStack Load Testing: +# Set 'projectName' to the name of your project. Example: 'Product ABC'. Tests under the same projectName will be grouped together. +projectName: Default Project + +# Set 'testName' to the name of your test. Example: 'First Load Test'. Test runs with the same testName will be grouped together. +testName: Default Test + +# ====================== +# Set Load Configuration +# ====================== +# The following parameters are used to set load configuration for your test: +# Set 'testType' to the type of load test that you want to execute. Example:'Playwright', 'Selenium'. This is a required parameter. +testType: Selenium + +# Set 'vus' to the maximum number of virtual users to simulate during the test. +vus: 1 + +# Set multiple regions from which you would want to generate the load (percent should total 100 across all loadzones). +regions: + - loadzone: us-east-1 + percent: 100 + +# Set language to the programming language used in your project. Example: 'java', 'nodejs'. +language: java + +# Set framework to the test framework used in your Selenium project. +framework: serenity-cucumber + +# Add list of file paths under 'dependencies' to help set up the test environment by installing required packages. Example: path to 'pom.xml' for Java projects using Maven, path to 'package.json' for Node.js projects. +# Add list of file paths under 'testConfigs' to define which configuration files should be used to run tests. Example: path to 'playwright.config.ts' for Playwright (Node.js), path to 'testng.xml' for Selenium (TestNG). +files: + dependencies: + - ./pom.xml + testConfigs: [] diff --git a/serenity-cucumber/pom.xml b/serenity-cucumber/pom.xml new file mode 100644 index 0000000..838c59c --- /dev/null +++ b/serenity-cucumber/pom.xml @@ -0,0 +1,121 @@ + + + 4.0.0 + com.example + selenium-serenity-cucumber-example + 1.0-SNAPSHOT + jar + + + 17 + 17 + UTF-8 + 4.15.0 + 4.2.16 + 7.20.1 + 5.10.1 + 1.10.1 + + + + + + org.seleniumhq.selenium + selenium-java + ${selenium.version} + + + + + net.serenity-bdd + serenity-core + ${serenity.version} + + + + + net.serenity-bdd + serenity-cucumber + ${serenity.version} + + + + + net.serenity-bdd + serenity-junit5 + ${serenity.version} + + + + + io.cucumber + cucumber-java + ${cucumber.version} + + + + + io.cucumber + cucumber-junit-platform-engine + ${cucumber.version} + + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + org.junit.platform + junit-platform-suite + ${junit.platform.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + + **/*Runner.java + **/*Test.java + **/*Tests.java + **/*TestCase.java + + false + + true + + + + + diff --git a/serenity-cucumber/src/test/java/com/example/RunCucumberTest.java b/serenity-cucumber/src/test/java/com/example/RunCucumberTest.java new file mode 100644 index 0000000..ad6a814 --- /dev/null +++ b/serenity-cucumber/src/test/java/com/example/RunCucumberTest.java @@ -0,0 +1,24 @@ +package com.example; + +import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.IncludeEngines; +import org.junit.platform.suite.api.SelectClasspathResource; +import org.junit.platform.suite.api.Suite; + +import static io.cucumber.core.options.Constants.GLUE_PROPERTY_NAME; +import static io.cucumber.core.options.Constants.PLUGIN_PROPERTY_NAME; + +/** + * JUnit 5 Platform Suite that runs all Cucumber feature files. + * Maven Surefire picks this class up via mvn test and executes the scenarios. + */ +@Suite +@IncludeEngines("cucumber") +@SelectClasspathResource("features") +@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example") +@ConfigurationParameter( + key = PLUGIN_PROPERTY_NAME, + value = "pretty, summary" +) +public class RunCucumberTest { +} diff --git a/serenity-cucumber/src/test/java/com/example/StepDefs.java b/serenity-cucumber/src/test/java/com/example/StepDefs.java new file mode 100644 index 0000000..6488aae --- /dev/null +++ b/serenity-cucumber/src/test/java/com/example/StepDefs.java @@ -0,0 +1,124 @@ +package com.example; + +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.net.URL; +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StepDefs { + + private WebDriver driver; + private String addedProductName; + private static final String HUB_URL = "http://localhost:4444/wd/hub"; + + @Before + public void setUp() throws Exception { + ChromeOptions chromeOptions = new ChromeOptions(); + chromeOptions.addArguments( + "--headless", + "--no-first-run", + "--no-default-browser-check", + "--disable-extensions", + "--disable-default-apps", + "--disable-gpu", + "--disable-dev-shm-usage", + "--disable-software-rasterizer", + "--no-sandbox", + "--disable-background-timer-throttling", + "--disable-backgrounding-occluded-windows", + "--disable-renderer-backgrounding", + "--disable-features=TranslateUI", + "--disable-ipc-flooding-protection", + "--disable-web-security", + "--disable-features=VizDisplayCompositor", + "--disable-logging", + "--silent" + ); + + driver = new RemoteWebDriver(new URL(HUB_URL), chromeOptions); + driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); + driver.manage().window().maximize(); + } + + @After + public void tearDown() { + if (driver != null) { + driver.quit(); + } + } + + @Given("I open the BrowserStack demo store") + public void iOpenTheBrowserStackDemoStore() { + driver.get("https://bstackdemo.com/"); + } + + @And("I sign in to BrowserStack demo") + public void iSignInToBrowserStackDemo() throws InterruptedException { + driver.findElement(By.id("signin")).click(); + driver.findElement(By.cssSelector("#username svg")).click(); + driver.findElement(By.id("react-select-2-option-0-0")).click(); + driver.findElement(By.cssSelector("#password svg")).click(); + driver.findElement(By.id("react-select-3-option-0-0")).click(); + driver.findElement(By.id("login-btn")).click(); + Thread.sleep(500); + } + + @When("I add the product at index {string} to my cart") + public void iAddTheProductAtIndexToMyCart(String index) { + WebElement productNameElem = driver.findElement(By.cssSelector("#\\3" + index + " > p")); + addedProductName = productNameElem.getText(); + WebElement addToCartBtn = driver.findElement(By.cssSelector("#\\3" + index + " > .shelf-item__buy-btn")); + addToCartBtn.click(); + } + + @Then("the same product should appear in my cart") + public void theSameProductShouldAppearInMyCart() { + By cartProductTitle = By.cssSelector( + "#__next > div > div > div.float-cart.float-cart--open > div.float-cart__content > div.float-cart__shelf-container > div > div.shelf-item__details > p.title" + ); + // The cart panel slides in async after the buy click; wait for its text to populate + // before asserting, otherwise getText() can return an empty string. + new WebDriverWait(driver, Duration.ofSeconds(10)) + .until(d -> !d.findElement(cartProductTitle).getText().isEmpty()); + assertEquals(addedProductName, driver.findElement(cartProductTitle).getText()); + } + + @And("I close the cart panel") + public void iCloseTheCartPanel() { + driver.findElement(By.cssSelector("div.float-cart__close-btn")).click(); + } + + @And("I proceed to checkout") + public void iProceedToCheckout() { + driver.findElement(By.cssSelector(".buy-btn")).click(); + } + + @And("I fill in the shipping address") + public void iFillInTheShippingAddress() { + driver.findElement(By.id("firstNameInput")).sendKeys("first"); + driver.findElement(By.id("lastNameInput")).sendKeys("last"); + driver.findElement(By.id("addressLine1Input")).sendKeys("address"); + driver.findElement(By.id("provinceInput")).sendKeys("province"); + driver.findElement(By.id("postCodeInput")).sendKeys("pincode"); + driver.findElement(By.id("checkout-shipping-continue")).click(); + } + + @Then("I should see the confirmation message {string}") + public void iShouldSeeTheConfirmationMessage(String expected) { + String message = driver.findElement(By.id("confirmation-message")).getText(); + assertEquals(expected, message); + } +} diff --git a/serenity-cucumber/src/test/resources/features/bstackdemo.feature b/serenity-cucumber/src/test/resources/features/bstackdemo.feature new file mode 100644 index 0000000..6d41a45 --- /dev/null +++ b/serenity-cucumber/src/test/resources/features/bstackdemo.feature @@ -0,0 +1,16 @@ +Feature: BrowserStack Demo cart and checkout + + Scenario: Add a product to the cart + Given I open the BrowserStack demo store + When I add the product at index "3" to my cart + Then the same product should appear in my cart + + Scenario: Complete a checkout + Given I open the BrowserStack demo store + And I sign in to BrowserStack demo + When I add the product at index "1" to my cart + And I close the cart panel + And I add the product at index "2" to my cart + And I proceed to checkout + And I fill in the shipping address + Then I should see the confirmation message "Your Order has been successfully placed."