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
111 changes: 111 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock
package-lock.json

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# IDE files
.idea/

**/target/
**/.DS_Store
80 changes: 78 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,78 @@
# cucumber-js-playwright-browserstack
Creating a sample repo for different Playwright languages and runners
# Running Playwright Tests with Cucumber.js on BrowserStack

Cucumber.js is a JavaScript-based open-source framework for web automation testing. It runs on Node.js and latest web browsers. Cucumber.js allows you to write and execute tests in Gherkin - a non-technical and human-readable language.

By default, Cucumber JS will automatically search for Step Definitions in the same folder as the feature files.

This repository provides an example setup for running Playwright tests with Cucumber.js on the BrowserStack cloud platform.

## Prerequisites

Before getting started, make sure you have the following prerequisites installed:

- [Node.js](https://nodejs.org) - The JavaScript runtime environment
- [npm](https://www.npmjs.com/) - The Node.js package manager
- [Playwright](https://playwright.dev/) - A Node.js library for browser automation

## Setup

1. Clone this repository to your local machine:

```bash
git clone https://github.com/browserstack/cucumber-js-playwright-browserstack.git
```

2. Install the dependencies by navigating to the project directory and running:


```bash
npm install
```

3. Set up your BrowserStack Environment variables

```plaintext
BROWSERSTACK_USERNAME=<your-browserstack-username>
BROWSERSTACK_ACCESS_KEY=<your-browserstack-access-key>
```

Replace `<your-browserstack-username>` and `<your-browserstack-access-key>` with your BrowserStack username and access key, which you can obtain from the BrowserStack dashboard.

## Browserstack Configuration
To view and update the Browser-OS combinations, please refer to the "features/steps/setup.js" file.

## Execution
To run the tests in parallel with different browser configurations, use the following command:

## Running your Tests:
To run a sample Test, run

```bash
npm run sample-test
```
This command will execute the Cucumber.js tests in parallel on Chrome and Edge browsers based on the configurations specified in the "features/steps/setup.js" file.`

## Run Test on Locally hosted Websites

```bash
npm sample-local-test
```

## Reporting

By default, Cucumber.js generates HTML reports in the `reports` directory after the test execution. You can open the HTML report in your browser to view the test results and detailed information.

## Conclusion

This repository provides a basic setup for running Playwright tests with Cucumber.js on the BrowserStack cloud platform. Feel free to modify and expand it based on your project requirements.

For more information on Playwright and Cucumber.js, refer to their respective documentation:

- [Playwright Documentation](https://playwright.dev/docs/intro)
- [Cucumber.js Documentation](https://github.com/cucumber/cucumber-js)

For additional details on configuring and using BrowserStack with Playwright, consult the BrowserStack documentation:

- [BrowserStack Documentation](https://www.browserstack.com/docs)

Happy testing!
4 changes: 4 additions & 0 deletions features/config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Object.assign(global, {
BASE_URL: 'https://bstackdemo.com/',
LOCAL_URL: 'https://www.example.com/'
});
4 changes: 4 additions & 0 deletions features/steps/assertions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const chai = require('chai');
global.expect = chai.expect;
global.assert = chai.assert;
global.should = chai.should;
108 changes: 108 additions & 0 deletions features/steps/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
const { setWorldConstructor, World, Before, After, Status, setDefaultTimeout } = require("@cucumber/cucumber");
const { chromium, devices } = require('playwright');
const cp = require('child_process');
const BrowserStackLocal = require('browserstack-local');
const playwrightClientVersion = cp.execSync('npx playwright --version').toString().trim().split(' ')[1];
setDefaultTimeout(120 * 1000);

const enableLocalTesting = false; // Set this flag to true to enable BrowserStack Local testing

const browserConfigs = [

{
browserName: 'chrome',
browserTagName: '@chrome',
browserVersion: 'latest',
os: 'OS X',
osVersion: 'Monterey',
resolution: '1280x1024',
},
{
browserName: 'playwright-firefox',
browserTagName: '@playwright-firefox',
browserVersion: 'latest',
os: 'Windows',
osVersion: '11',
resolution: '1280x1024',
},
{
browserName: 'edge',
browserTagName: '@edge',
browserVersion: 'latest',
os: 'OS X',
osVersion: 'Ventura',
resolution: '1280x1024',
},
];

const browserConnections = [];

Before(async (scenario) => {
const tagName = scenario.pickle.tags[0].name;
const filteredBrowserConfigs = browserConfigs.filter(config => config.browserTagName === tagName);

for (const browserConfig of filteredBrowserConfigs) {
const caps = {
...browserConfig,
'browserstack.username': process.env.BROWSERSTACK_USERNAME || 'YOUR_USERNAME',
'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY || 'YOUR_ACCESS_KEY',
'project': 'PLAYWRIGHT-CUCUMBER-JS',
'build': 'playwright-cucumber-build-1',
'name': scenario.pickle.name,
'buildTag': 'Regression',
'browserstack.playwrightVersion': '1.latest',
'client.playwrightVersion': '1.latest'
};

console.log('enableLocalTesting', enableLocalTesting);
if (enableLocalTesting && browserConnections.length === 0) {
const bsLocal = new BrowserStackLocal.Local();
const bsLocalArgs = {
key: process.env.BROWSERSTACK_ACCESS_KEY, // Replace with your BrowserStack access key
localIdentifier: 'local_connection_name' // Replace with your desired local connection name
};

await new Promise((resolve, reject) => {
bsLocal.start(bsLocalArgs, (error) => {
if (error) {
console.error('Failed to start BrowserStack Local:', error);
reject(error);
} else {
console.log('BrowserStack Local started successfully');
resolve();
}
});
});
}

// Create page and browser globals to be used in the scenarios
const browser = await chromium.connect({
wsEndpoint: `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`,
});

const context = await browser.newContext();
global.page = await context.newPage();

browserConnections.push(browser);
}
});

After(async () => {
await Promise.all(browserConnections.map(browser => browser.close()));
});

After(async (scenario) => {
if (scenario.result.status === Status.PASSED) {
await page.evaluate(_ => { }, `browserstack_executor: ${JSON.stringify({ action: 'setSessionStatus', arguments: { status: 'passed', reason: 'Test Passed' } })}`);
} else if (scenario.result.status === Status.FAILED) {
await page.evaluate(_ => { }, `browserstack_executor: ${JSON.stringify({ action: 'setSessionStatus', arguments: { status: 'failed', reason: 'Test Failed' } })}`);
}
});

setWorldConstructor(function () {
this.testCaseRetry = 2; // Set the number of retries for each test case
});

module.exports = {
parallel: 2, // Set the number of parallel test workers to the number of browsers
};
48 changes: 48 additions & 0 deletions features/steps/viewBrowserstack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const { Given, When, Then } = require("@cucumber/cucumber");
const { HomePage } = require('../../page-objects/home-page')
const { LoginPage } = require('../../page-objects/login-page')
const { CheckoutPage } = require('../../page-objects/checkout-page')
const homePage = new HomePage();
const loginPage = new LoginPage();
const checkoutPage = new CheckoutPage();

Given("Open BrowserStack Demo website", { timeout: 60 * 1000 }, async function () {
await homePage.navigateToAutomate();
await homePage.verifyHomePageIsDisplayed();
});

Given("Open local hosted website", { timeout: 60 * 1000 }, async function () {
await homePage.navigateToLocalWebsite();
});

Given('I SignIn as {string} with {string} password', async function (username, password) {
await homePage.clickSignIn();
await loginPage.submitLoginForm(username, password);
await homePage.verifyAfterLoginPage();
});

When("I add iPhone 12 to cart", async function () {
await homePage.clickProduct();
// Click Checkout
await page.click("text=Checkout");
});

When("I add the shipping address and submit the details", async function (dataTable) {
const userPromises = dataTable.hashes().map(async (element) => {
await checkoutPage.setUserDetails(element.FirstName, element.LastName, element.Address, element.State, element.PostalCode);
});

await Promise.all(userPromises);
});

Then("I should see product has been placed successfully", async function () {
await checkoutPage.clickSubmit();
await wait(3000);
await checkoutPage.verifyConfirmationMessage();
});

function wait(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}
6 changes: 6 additions & 0 deletions features/view-browserstack-local.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature: Execute the Test in Local Environment

@browser:1
Scenario: Verify if User is able run on the local server
Given Open local hosted website

21 changes: 21 additions & 0 deletions features/view-browserstack.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Feature: View BrowserStack Demo Site

@chrome
Scenario: Verify if User is able to place the Order
Given Open BrowserStack Demo website
And I SignIn as "fav_user" with "testingisfun99" password
When I add iPhone 12 to cart
And I add the shipping address and submit the details
| FirstName | LastName | Address | State | PostalCode |
| Demo | User | H.no 123 | Telangana | 500019 |
Then I should see product has been placed successfully

@edge
Scenario: Verify if User is able to place the Order on Edge
Given Open BrowserStack Demo website
And I SignIn as "fav_user" with "testingisfun99" password
When I add iPhone 12 to cart
And I add the shipping address and submit the details
| FirstName | LastName | Address | State | PostalCode |
| Demo | User | H.no 123 | Telangana | 500019 |
Then I should see product has been placed successfully
Loading