diff --git a/.gitignore b/.gitignore index 1120b9d..4f9bd77 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ **/log **/browserstack-cli **/.DS_Store +**/node_modules/ +**/package-lock.json +**/yarn.lock +**/pnpm-lock.yaml diff --git a/jest/README.md b/jest/README.md new file mode 100644 index 0000000..2ec0072 --- /dev/null +++ b/jest/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 jest + ``` + +2. **Install Node dependencies** + + ```sh + npm install + ``` + +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/jest/browserstack-load.yml b/jest/browserstack-load.yml new file mode 100644 index 0000000..d2a0889 --- /dev/null +++ b/jest/browserstack-load.yml @@ -0,0 +1,48 @@ +# ============================= +# 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 'duration' to the total duration of the entire test, in minutes and seconds. The test will run infinite iterations until the duration is met. Example: '2m', '3m 40s'. This is not a required parameter. +duration: 1m + +# 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: nodejs + +# Set framework to the test framework used in your Selenium project. +framework: jest + +# 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: + - ./package.json + testConfigs: + - ./jest.config.js diff --git a/jest/jest.config.js b/jest/jest.config.js new file mode 100644 index 0000000..aa683f6 --- /dev/null +++ b/jest/jest.config.js @@ -0,0 +1,8 @@ +// Jest runs with --runInBand on BrowserStack so the single Selenium session +// per pod is never contended. testEnvironment must be "node" — Jest drives a +// remote WebDriver, not the in-process DOM. +module.exports = { + testEnvironment: "node", + testMatch: ["**/tests/**/*.test.js", "**/?(*.)+(spec|test).js"], + testTimeout: 120000, +}; diff --git a/jest/package.json b/jest/package.json new file mode 100644 index 0000000..771a186 --- /dev/null +++ b/jest/package.json @@ -0,0 +1,13 @@ +{ + "name": "browserstack-jest-load-testing-sample", + "version": "1.0.0", + "private": true, + "description": "Sample Jest + selenium-webdriver project for BrowserStack Load Testing", + "scripts": { + "test": "jest --runInBand --passWithNoTests=false" + }, + "dependencies": { + "jest": "^29.7.0", + "selenium-webdriver": "^4.21.0" + } +} diff --git a/jest/tests/add-to-cart.test.js b/jest/tests/add-to-cart.test.js new file mode 100644 index 0000000..4d9abb0 --- /dev/null +++ b/jest/tests/add-to-cart.test.js @@ -0,0 +1,46 @@ +const { Builder, By } = require("selenium-webdriver"); + +// On BrowserStack Load Testing, the Selenium pod exposes a hub at +// http://localhost:4444/wd/hub. A plain `forBrowser("chrome").build()` +// would try to spawn a local browser the pod does not have. +const HUB_URL = "http://localhost:4444/wd/hub"; + +describe("BStackDemo test add to cart", () => { + let driver; + + beforeAll(async () => { + driver = await new Builder() + .usingServer(HUB_URL) + .forBrowser("chrome") + .build(); + }); + + afterAll(async () => { + if (driver) await driver.quit(); + }); + + test("should add product to cart successfully", async () => { + // visit the site + await driver.get("https://bstackdemo.com/"); + + // get name of product we want to add to cart + const productElement = await driver.findElement(By.css("#\\33 > p")); + const productToAdd = await productElement.getText(); + + // click on add to cart + await driver.findElement(By.css("#\\33 > .shelf-item__buy-btn")).click(); + + // get name of item in cart + const cartItemElement = await driver.findElement( + By.css( + "#__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", + ), + ); + const productInCart = await cartItemElement.getText(); + + // check if product in cart is same as one added + expect(productInCart).toBe(productToAdd); + }); +}); diff --git a/jest/tests/checkout.test.js b/jest/tests/checkout.test.js new file mode 100644 index 0000000..be55de8 --- /dev/null +++ b/jest/tests/checkout.test.js @@ -0,0 +1,55 @@ +const { Builder, By } = require("selenium-webdriver"); + +const HUB_URL = "http://localhost:4444/wd/hub"; + +describe("BStackDemo test checkout flow", () => { + let driver; + + beforeAll(async () => { + driver = await new Builder() + .usingServer(HUB_URL) + .forBrowser("chrome") + .build(); + }); + + afterAll(async () => { + if (driver) await driver.quit(); + }); + + test("should complete checkout flow successfully", async () => { + // visit the site + await driver.get("https://bstackdemo.com/"); + + // sign in + await driver.findElement(By.id("signin")).click(); + await driver.findElement(By.css("#username svg")).click(); + await driver.findElement(By.id("react-select-2-option-0-0")).click(); + await driver.findElement(By.css("#password svg")).click(); + await driver.findElement(By.id("react-select-3-option-0-0")).click(); + + await driver.findElement(By.id("login-btn")).click(); + await driver.sleep(500); + + // click on buy item + await driver.findElement(By.css("#\\31 > .shelf-item__buy-btn")).click(); + await driver.findElement(By.css(".float-cart__close-btn")).click(); + await driver.findElement(By.css("#\\32 > .shelf-item__buy-btn")).click(); + await driver.findElement(By.css(".buy-btn")).click(); + + // add address details + await driver.findElement(By.id("firstNameInput")).sendKeys("first"); + await driver.findElement(By.id("lastNameInput")).sendKeys("last"); + await driver.findElement(By.id("addressLine1Input")).sendKeys("address"); + await driver.findElement(By.id("provinceInput")).sendKeys("province"); + await driver.findElement(By.id("postCodeInput")).sendKeys("pincode"); + + // checkout + await driver.findElement(By.id("checkout-shipping-continue")).click(); + await driver + .findElement(By.xpath("//*[contains(text(),'Continue')]")) + .click(); + await driver + .findElement(By.xpath("//*[contains(text(),'Orders')]")) + .click(); + }); +});