Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions serenity-cucumber/README.md
Original file line number Diff line number Diff line change
@@ -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.

---
44 changes: 44 additions & 0 deletions serenity-cucumber/browserstack-load.yml
Original file line number Diff line number Diff line change
@@ -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: []
121 changes: 121 additions & 0 deletions serenity-cucumber/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>selenium-serenity-cucumber-example</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<selenium.version>4.15.0</selenium.version>
<serenity.version>4.2.16</serenity.version>
<cucumber.version>7.20.1</cucumber.version>
<junit.jupiter.version>5.10.1</junit.jupiter.version>
<junit.platform.version>1.10.1</junit.platform.version>
</properties>

<dependencies>
<!-- Selenium WebDriver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>

<!-- Serenity BDD core -->
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
</dependency>

<!-- Serenity Cucumber integration -->
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber</artifactId>
<version>${serenity.version}</version>
</dependency>

<!-- Serenity JUnit 5 integration -->
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-junit5</artifactId>
<version>${serenity.version}</version>
</dependency>

<!-- Cucumber JVM runtime -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>

<!-- Cucumber JUnit 5 platform engine -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
</dependency>

<!-- JUnit Jupiter API & Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>

<!-- JUnit 5 Platform Suite (used by the Cucumber runner class) -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>${junit.platform.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<!-- Cucumber JUnit5 Suite runners commonly use either the
*Test.java or *Runner.java naming convention. Surefire's
default include pattern only catches Test*/Tests/TestCase
names, so a runner renamed to e.g. CucumberTestRunner.java
would be skipped — combined with failIfNoTests=true that
surfaces to the LT pod as errorType=initialization with
no log artifacts. Listing both conventions makes the
build robust to runner-class renames. -->
<includes>
<include>**/*Runner.java</include>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
<include>**/*TestCase.java</include>
</includes>
<useModulePath>false</useModulePath>
<!-- Fail the build if zero scenarios execute (e.g., when every Cucumber scenario
is tagged @ignore). Without this, Maven exits 0 with no work done and the
load test reports a false success. -->
<failIfNoTests>true</failIfNoTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -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 {
}
124 changes: 124 additions & 0 deletions serenity-cucumber/src/test/java/com/example/StepDefs.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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."