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
89 changes: 89 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Runs the behave + Playwright sample against BrowserStack SDK on workflow_dispatch.
# Mirrors the pattern from browserstack/cucumber-java-playwright-browserstack:
# triggered manually with a commit SHA, posts check statuses back to that SHA so
# results show up on PRs without binding to push/pull_request triggers.

name: Behave Playwright SDK Test workflow on workflow_dispatch

on:
workflow_dispatch:
inputs:
commit_sha:
description: 'The full commit id to build'
required: true

permissions:
contents: read

jobs:
sample-run:
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
name: Behave Playwright Sample
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit_sha }}

- uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
id: status-check-in-progress
env:
job_name: Behave Playwright Sample
commit_sha: ${{ github.event.inputs.commit_sha }}
with:
github-token: ${{ github.token }}
script: |
const result = await github.rest.checks.create({
owner: context.repo.owner,
repo: context.repo.repo,
name: process.env.job_name,
head_sha: process.env.commit_sha,
status: 'in_progress'
}).catch((err) => ({status: err.status, response: err.response}));
console.log(`The status-check response : ${result.status} Response : ${JSON.stringify(result.response)}`)
if (result.status !== 201) {
console.log('Failed to create check run')
}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
cache: pip

- name: Install dependencies
run: |
pip install -r requirements.txt
playwright install chromium

- name: Run sample on BrowserStack
run: browserstack-sdk behave features/sample.feature

- if: always()
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
id: status-check-completed
env:
conclusion: ${{ job.status }}
job_name: Behave Playwright Sample
commit_sha: ${{ github.event.inputs.commit_sha }}
with:
github-token: ${{ github.token }}
script: |
const result = await github.rest.checks.create({
owner: context.repo.owner,
repo: context.repo.repo,
name: process.env.job_name,
head_sha: process.env.commit_sha,
status: 'completed',
conclusion: process.env.conclusion
}).catch((err) => ({status: err.status, response: err.response}));
console.log(`The status-check response : ${result.status} Response : ${JSON.stringify(result.response)}`)
if (result.status !== 201) {
console.log('Failed to create check run')
}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.venv/
__pycache__/
*.pyc
log/
local.log
55 changes: 53 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,53 @@
# behave-playwright-browserstack
Sample repo for customers
behave-playwright-browserstack (BrowserStack SDK + Playwright)
===============================================================

This repo shows how to run [behave](https://behave.readthedocs.io/) tests on BrowserStack using the [BrowserStack Python SDK](https://pypi.org/project/browserstack-sdk/) and [Playwright Python](https://playwright.dev/python/). The SDK handles capability injection, BrowserStack routing for Playwright launches, parallelization, and BrowserStack Local for you — you describe platforms once in `browserstack.yml` and run the test command unchanged.

## Setup
* Clone this repo
* Install dependencies (creates the BrowserStack SDK CLI on `PATH` and downloads Playwright Chromium)
```sh
pip install -r requirements.txt
playwright install chromium
```
* Set `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` as environment variables, or replace `userName` and `accessKey` directly in `browserstack.yml` with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings). Env vars take precedence.

### Running your tests
Run the sample in parallel across the 3 Playwright browser engines (chromium / firefox / webkit) declared in `browserstack.yml`:

```sh
browserstack-sdk behave features/sample.feature
```

Understand how many parallel sessions you need by using our [Parallel Test Calculator](https://www.browserstack.com/automate/parallel-calculator?ref=github).

Alternatively the variables can be set in the environment using env or your CI framework (like GitHub Actions or Jenkins). See `.github/workflows/build.yml` for a GitHub Actions example — it runs on `workflow_dispatch` (manual trigger) with a commit SHA input and posts a status check back to that commit.

### Testing a private host (BrowserStack Local)
If your app lives on `localhost`, a staging host, or behind a firewall, set `browserstackLocal: true` in `browserstack.yml` and rerun the same command. The SDK starts and stops the BrowserStack Local tunnel for you — no manual binary download or lifecycle management. Then point your scenarios at `http://bs-local.com:<port>/` (a hostname BrowserStack Local resolves to your machine) instead of a public URL.

### How the SDK changes things
- **One `browserstack.yml`** declares platforms; the SDK picks them up automatically.
- **The SDK runs platforms in parallel for you** — no hand-rolled parallel runner; the SDK forks one behave run per `(platform × parallelsPerPlatform)` cell.
- **The SDK monkeypatches Playwright's browser launches** — the test code calls `chromium.launch()` and the SDK transparently routes the launch to the per-platform browser configured in `browserstack.yml` (chromium, firefox, or webkit). No `chromium.connect(wss_url)` plumbing is needed in customer code.
- **The CLI is `browserstack-sdk behave …`** — wraps `behave` and injects the SDK at runtime.

### Repo layout
```
.
├── browserstack.yml # SDK config: credentials, 3 parallel platforms, Local toggle, reporting
├── requirements.txt
└── features/
├── sample.feature # bstackdemo add-to-cart scenario
├── environment.py # behave hooks: launch browser, hand to context.page
└── steps/
└── sample_steps.py
```

### Further Reading
- [behave](https://behave.readthedocs.io/)
- [Playwright Python](https://playwright.dev/python/)
- [BrowserStack documentation for Playwright](https://www.browserstack.com/docs/automate/playwright)
- [BrowserStack Python SDK on PyPI](https://pypi.org/project/browserstack-sdk/)

Happy Testing!
Comment thread
Jimesh-browserstack marked this conversation as resolved.
59 changes: 59 additions & 0 deletions browserstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# =============================
# Set BrowserStack Credentials
# =============================
# Add your BrowserStack userName and accessKey here, or set the
# BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY environment
# variables. Env vars take precedence over the values in this file.
userName: YOUR_USERNAME
accessKey: YOUR_ACCESS_KEY

# ======================
# BrowserStack Reporting
# ======================
projectName: BrowserStack Samples
buildName: behave-playwright-sdk-build-1

# `framework` lets the SDK send test context (test name, status) to BrowserStack.
framework: behave

# =======================================
# Platforms (Browsers / Devices to test)
# =======================================
# Each entry below is one cross-browser cell. The SDK runs `parallelsPerPlatform`
# parallel sessions per entry, so the three entries below x 1 = 3 parallel sessions.
# These three browsers map 1:1 to the three Playwright engine families (chromium /
# firefox / webkit). The customer code in features/environment.py calls
# `chromium.launch()` — the SDK transparently routes the launch to the correct
# per-platform browser at runtime, so no per-platform branching is needed.
platforms:
- os: Windows
osVersion: 11
browserName: chrome
browserVersion: latest
- os: Windows
osVersion: 11
browserName: playwright-firefox
browserVersion: latest
- os: OS X
osVersion: Sonoma
browserName: playwright-webkit
browserVersion: latest

parallelsPerPlatform: 1

# ===================================
# BrowserStack Local (private hosts)
# ===================================
# Set to true to test localhost / staging hosts. The SDK starts and stops
# the BrowserStack Local tunnel for you — no manual binary management.
browserstackLocal: false

# ===========
# Diagnostics
# ===========
debug: true
networkLogs: false
consoleLogs: errors

# Identifier so BrowserStack can tag the sample source — please leave as-is.
source: behave-playwright-browserstack:sample-main:v1.0
18 changes: 18 additions & 0 deletions features/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from playwright.sync_api import sync_playwright


def before_scenario(context, scenario):
# Customer code calls `chromium.launch()` directly. The BrowserStack SDK
# monkeypatches Playwright at runtime so this launch is routed to the
# browser configured in the platform entry the SDK is currently driving
# — works unchanged for chromium, firefox, and webkit platforms.
context.pw = sync_playwright().start()
context.browser = context.pw.chromium.launch()
context.page = context.browser.new_page()


def after_scenario(context, scenario):
try:
context.browser.close()
finally:
context.pw.stop()
6 changes: 6 additions & 0 deletions features/sample.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature: Browserstack test

Scenario: Can add the product in cart
Given I visit bstackdemo website
When I add a product to the cart
Then I should see same product in cart section
27 changes: 27 additions & 0 deletions features/steps/sample_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from behave import given, when, then


@given("I visit bstackdemo website")
def visit_bstackdemo(context):
context.page.goto("https://www.bstackdemo.com/")
assert context.page.title() == "StackDemo"


@when("I add a product to the cart")
def add_product(context):
product_locator = context.page.locator('xpath=//*[@id="1"]/p')
context.product_on_page_text = product_locator.text_content()
context.page.locator('xpath=//*[@id="1"]/div[4]').click()


@then("I should see same product in cart section")
def verify_cart(context):
cart = context.page.locator('xpath=//*[@class="float-cart__content"]')
cart.wait_for(state="visible")
cart_product_locator = context.page.locator(
'xpath=//*[@id="__next"]/div/div/div[2]/div[2]/div[2]/div/div[3]/p[1]'
)
product_on_cart_text = cart_product_locator.text_content()
assert product_on_cart_text == context.product_on_page_text, (
f"expected {context.product_on_page_text!r} in cart, got {product_on_cart_text!r}"
)
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
browserstack-sdk>=1.46.0
behave>=1.2.7
playwright==1.49.0
Loading