Implementing BDD with `pytest-bdd` and `pytest-playwright` for Web Testing
Tags: bdd, pytestbdd, pytestplaywright, cuccumber
Published: 2024-07-01 04:12:29

---
title: Implementing BDD with `pytest-bdd` and `pytest-playwright` for Web Testing
published: true
description: A tutorial to learn bdd using pytest-bdd and pytest-playwright
tags: bdd, pytestbdd, pytestplaywright, cuccumber
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-07-01 03:11 +0000
---
## Introduction
Behavior-Driven Development (BDD) is a software development process that enhances communication between developers, testers, and non-technical stakeholders. It uses simple, natural language syntax to describe the behavior of the application, making it easier for everyone to understand the requirements and the expected behavior.

### Example of BDD
Consider a simple feature of logging into a web application. In BDD, this might be described in a feature file using Gherkin syntax as follows:

```gherkin
Feature: User Login

  Scenario: Successful login with valid credentials
    Given the user is on the login page
    When the user enters valid credentials
    Then the user should be redirected to the dashboard
```

In this example, the behavior of the login feature is clearly described in a way that both technical and non-technical stakeholders can understand.

### References
- **BDD Overview:** [Cucumber BDD](https://cucumber.io/docs/bdd/)
- **pytest Documentation:** [pytest](https://docs.pytest.org/en/stable/)
- **pytest-bdd Documentation:** [pytest-bdd](https://pytest-bdd.readthedocs.io/en/stable/)
- **Playwright Documentation:** [Playwright](https://playwright.dev/python/docs/intro)
- **pytest-playwright Documentation:** [pytest-playwright](https://github.com/microsoft/playwright-pytest)

## Prerequisites
- Basic knowledge of Python
- Familiarity with pytest and web automation concepts
- Python installed on your machine

## Step 1: Setting Up the Environment

### Installing Required Packages
First, install the necessary packages:
```sh
pip install pytest pytest-bdd pytest-playwright
```

## Step 2: Project Structure
Create a structured project directory as follows:
```
tutorial/
├── features/
│   ├── login.feature
│   ├── search_stock.feature
│   └── create_screen.feature
├── tests/
│   ├── test_a_login.py
│   ├── test_search_stock.py
│   └── test_create_screen.py
├── conftest.py
└── utils/
    └── config.py
```

## Step 3: Writing Feature Files
Feature files define the behavior you want to test using Gherkin syntax.

### `features/login.feature`
```gherkin
Feature: Login to Screener.in

  Scenario: Log into Screener.in
    Given the user is on the login page
    When the user logs in with valid credentials
    Then the user should be redirected to the dashboard
```

### `features/search_stock.feature`
```gherkin
Feature: Search for a stock and get the P/E ratio

  Scenario Outline: Search for a stock by name and retrieve the P/E ratio
    Given the user is logged in
    When the user searches for "<stock_name>"
    Then the P/E ratio for "<stock_name>" should be displayed

  Examples:
    | stock_name      |
    | NESTLEIND       |
    | PGHH            |
    | LICI            |
    | TCS             |
    | BRITANNIA       |
```

### `features/create_screen.feature`
```gherkin
Feature: Create a new screen for quality stocks

  Scenario: Create a new screen with filtering stocks greater than market capital 50000Cr
    Given the user is logged in
    When the user creates a new screen with filtering stocks greater than market capital 50000Cr
    Then the new screen should be created successfully
```

## Step 4: Writing Step Definitions
Step definitions map the steps in your feature files to Python functions.

### `tests/test_a_login.py`
```python
import pytest
from pytest_bdd import scenarios, given, when, then

scenarios('../features/login.feature')

@given('the user is on the login page')
def navigate_to_login_page(page):
    page.goto("https://www.screener.in/login/")

@when('the user logs in with valid credentials')
def login_with_valid_credentials(login):
    pass  # The login fixture handles the login

@then('the user should be redirected to the dashboard')
def verify_dashboard(login):
    assert login.url == "https://www.screener.in/dash/"
```

### `tests/test_search_stock.py`
```python
import pytest
from pytest_bdd import scenarios, given, when, then, parsers
from playwright.sync_api import Page
import time

scenarios('../features/search_stock.feature')

@given('the user is logged in')
def user_logged_in(login):
    pass  # The login fixture ensures the user is logged in

@when(parsers.parse('the user searches for "{stock_name}"'))
def search_stock(login: Page, stock_name):
    login.click('//*[@id="desktop-search"]/div/input')
    login.fill('//*[@id="desktop-search"]/div/input', stock_name)
    login.click('//*[@id="desktop-search"]/div/div/button')

@then(parsers.parse('the P/E ratio for "{stock_name}" should be displayed'))
def verify_pe_ratio(login: Page, stock_name):
    pe_ratio = login.locator('//*[@id="top-ratios"]/li[4]/span[2]')
    assert pe_ratio.is_visible()
    print(f"P/E Ratio for {stock_name}: {pe_ratio.text_content()}")
    time.sleep(5)
```

### `tests/test_create_screen.py`
```python
import pytest
from pytest_bdd import scenarios, given, when, then
from playwright.sync_api import Page

scenarios("../features/create_screen.feature")

@given("the user is logged in")
def user_logged_in(login):
    pass  # The login fixture ensures the user is logged in

@when("the user creates a new screen with filtering stocks greater than market capital 50000Cr")
def create_new_screen(login: Page):
    login.click("//a[@href='/explore/' and text()='Screens']")
    login.click("//a[@class='button button-primary' and @href='/screen/new/']")
    login.fill(
        'textarea[name="query"]',
        """Market Capitalization > 50000""",
    )
    login.click("//button[@class='button-primary']")

@then("the new screen should be created successfully")
def verify_new_screen_creation(login: Page):
    assert login.locator("text=Nestle India").is_visible()
```

## Step 5: Configuring `pytest-playwright`
Set up Playwright in your `conftest.py` to handle browser instances.

### `conftest.py`
```python
import pytest
from playwright.sync_api import sync_playwright
from utils.config import USERNAME, PASSWORD

@pytest.fixture(scope="session")
def browser():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        yield browser
        browser.close()

@pytest.fixture(scope="session")
def context(browser):
    context = browser.new_context()
    yield context
    context.close()

@pytest.fixture(scope="session")
def page(context):
    page = context.new_page()
    yield page
    page.close()

@pytest.fixture(scope="session")
def login(page):
    page.goto("https://www.screener.in/login/")
    page.fill('input[name="username"]', USERNAME)
    page.fill('input[name="password"]', PASSWORD)
    page.click('button[type="submit"]')
    assert page.url == "https://www.screener.in/dash/"
    yield page
```

### `utils/config.py`
Ensure you have your credentials stored securely:
```python
USERNAME = "your_username"
PASSWORD = "your_password"
```

## Step 6: Running the Tests
To run your tests, simply use the `pytest` command:
```sh
pytest
```

## Conclusion
This tutorial provided a detailed introduction to setting up and using `pytest-bdd` and `pytest-playwright` for BDD testing. By following the steps above, you can create robust and readable tests for your web applications.

Feel free to extend this setup to include more complex scenarios and additional utilities as needed. This setup provides a solid foundation for using `pytest-bdd` and `pytest-playwright` in your projects.

### References
- **BDD Overview:** [Cucumber BDD](https://cucumber.io/docs/bdd/)
- **pytest Documentation:** [pytest](https://docs.pytest.org/en/stable/)
- **pytest-bdd Documentation:** [pytest-bdd](https://pytest-bdd.readthedocs.io/en/stable/)
- **Playwright Documentation:** [Playwright](https://playwright.dev/python/docs/intro)
- **pytest-playwright Documentation:** [pytest-playwright](https://github.com/microsoft/playwright-pytest)

---

By following this guide, you'll be well on your way to implementing effective BDD-style tests for your web applications. Happy testing!