# Implement Keyword Driven Testing

> Implement keyword-driven testing framework for reduced code duplication and increased test coverage. Use when: creating reusable test keywords, implementing high-level business logic, reducing test code complexity, enabling non-technical team members to write tests.

- Skill: `bavithiranhardy14/implement-keyword-driven-testing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add bavithiranhardy14/implement-keyword-driven-testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bavithiranhardy14/implement-keyword-driven-testing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: bavithiranhardy14 (https://skillmd.com/u/bavithiranhardy14)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/bavithiranhardy14/implement-keyword-driven-testing

---


# Implement Keyword-Driven Testing

## When to Use

- Reducing test code duplication
- Enabling non-technical team members to create tests
- Implementing high-level business operations
- Creating reusable test keywords
- Building domain-specific languages for tests
- Large test suites with similar operations

## Procedure

### 1. Create Base Keyword Class

**keywords/base_keyword.py**

```python
from utils.logger import get_logger
import inspect

logger = get_logger(__name__)

class BaseKeyword:
    """Base class for all keywords."""
    
    def log_keyword_call(self, *args, **kwargs):
        logger.info(f"Executing keyword: {self.__class__.__name__}")
        logger.debug(f"Args: {args}, Kwargs: {kwargs}")
    
    def __call__(self, *args, **kwargs):
        self.log_keyword_call(*args, **kwargs)
        return self.execute(*args, **kwargs)
    
    def execute(self, *args, **kwargs):
        raise NotImplementedError("execute() must be implemented")
```

### 2. Create UI Keywords for Playwright

**keywords/ui_keywords.py**

```python
from keywords.base_keyword import BaseKeyword
from pages.login_page import LoginPage
from pages.dashboard_page import DashboardPage
from utils.logger import get_logger

logger = get_logger(__name__)

class OpenPage(BaseKeyword):
    """Open a URL in the browser."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, url: str) -> bool:
        self.page.goto(url)
        logger.info(f"Opened: {url}")
        return True

class LoginAsUser(BaseKeyword):
    """Login with username and password."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, username: str, password: str) -> bool:
        login = LoginPage(self.page)
        login.login(username, password)
        logger.info(f"Logged in as {username}")
        return True

class VerifyDashboardLoaded(BaseKeyword):
    """Verify user is on the dashboard."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self) -> bool:
        dashboard = DashboardPage(self.page)
        result = dashboard.is_user_logged_in()
        logger.info(f"Dashboard loaded: {result}")
        return result

class ClickElement(BaseKeyword):
    """Click element by CSS selector."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, selector: str) -> bool:
        self.page.click(selector)
        logger.info(f"Clicked: {selector}")
        return True

class FillField(BaseKeyword):
    """Fill input field with text."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, selector: str, text: str) -> bool:
        self.page.fill(selector, text)
        logger.info(f"Filled {selector}")
        return True

class VerifyTextVisible(BaseKeyword):
    """Verify text is visible on page."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, text: str) -> bool:
        found = self.page.is_visible(f"text={text}")
        logger.info(f"Text '{text}' visible: {found}")
        return found

class TakeScreenshot(BaseKeyword):
    """Take screenshot with given name."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, name: str) -> bool:
        self.page.screenshot(path=f"reports/screenshots/{name}.png")
        logger.info(f"Screenshot saved: {name}")
        return True

class WaitForElement(BaseKeyword):
    """Wait for element to be visible."""
    
    def __init__(self, page):
        self.page = page
    
    def execute(self, selector: str, timeout: int = 10000) -> bool:
        try:
            self.page.wait_for_selector(selector, timeout=timeout)
            logger.info(f"Element visible: {selector}")
            return True
        except Exception:
            logger.warning(f"Element not found: {selector}")
            return False
```

### 3. Use Keywords in Tests

**tests/ui/test_login_keywords.py**

```python
import pytest
from keywords.ui_keywords import (
    OpenPage,
    LoginAsUser,
    VerifyDashboardLoaded,
    TakeScreenshot
)

class TestLoginKeywords:
    
    @pytest.fixture(autouse=True)
    def setup(self, page):
        self.pw_page = page.page
    
    @pytest.mark.smoke
    def test_login_flow(self):
        # Plain-English keyword calls — readable by anyone
        OpenPage(self.pw_page).execute("https://app.example.com/login")
        LoginAsUser(self.pw_page).execute("admin@example.com", "pass123")
        assert VerifyDashboardLoaded(self.pw_page).execute()
        TakeScreenshot(self.pw_page).execute("post_login")
    
    @pytest.mark.regression
    def test_failed_login(self):
        from keywords.ui_keywords import VerifyTextVisible
        
        OpenPage(self.pw_page).execute("https://app.example.com/login")
        LoginAsUser(self.pw_page).execute("user@example.com", "wrongpass")
        assert VerifyTextVisible(self.pw_page).execute("Invalid credentials")
```

## Best Practices

- Keywords map to **business actions**, not technical steps
- Each keyword does ONE thing
- Non-technical team members can read and write tests
- Reuse keywords across dozens of test cases
- Keywords abstract away Playwright API details

