write-robot-tests

star 651

Write or review Robot Framework acceptance tests for the Browser library. Use when: creating new .robot test files, adding test cases, writing user keywords, writing library keywords in atest/library/, or reviewing existing tests for rule compliance.

MarketSquare By MarketSquare schedule Updated 3/7/2026

name: write-robot-tests description: 'Write or review Robot Framework acceptance tests for the Browser library. Use when: creating new .robot test files, adding test cases, writing user keywords, writing library keywords in atest/library/, or reviewing existing tests for rule compliance.' argument-hint: 'Describe what to test or point to the file to create/review'

Write Robot Framework Tests

These rules apply to acceptance tests in the atest/ folder.

Rules

Tests and user keywords must be self-explanatory

Test case names and keyword calls must read like plain English. No reader should need to look at an implementation to understand the intent. Choose names that describe what is being verified, not how.

Good

*** Test Cases ***
Login Fails With Wrong Password
    Go To    ${LOGIN_URL}
    Fill Text    input#username_field    wrong_user
    Fill Secret    input#password_field    $wrong_password
    Click    css=input#login_button
    Get Text    css=.error-message    ==    Login failed. Invalid user name and/or password.

Bad — name says nothing specific, comment compensates for a weak name

*** Test Cases ***
Test Login
    # Verify that login with incorrect credentials shows an error
    Go To    ${LOGIN_URL}
    Fill Text    input#username_field    wrong_user
    Fill Secret    input#password_field    $wrong_password
    Click    css=input#login_button
    Get Text    css=.error-message    ==    Login failed. Invalid user name and/or password.

No [Documentation] in test cases or user keywords

Test cases and user keywords defined in .robot files must not use [Documentation]. The name and structure must be sufficient. Inline comments (#) are acceptable sparingly for genuinely non-obvious details — they are the exception, not the rule.

Good

*** Keywords ***
Login User
    Fill Text    input#username_field    demo
    Fill Secret    input#password_field    $mode
    Click    css=input#login_button

Bad

*** Keywords ***
Login User
    [Documentation]    Fills in credentials and submits the login form.
    Fill Text    input#username_field    demo
    Fill Secret    input#password_field    $mode
    Click    css=input#login_button

Library keywords may have documentation

Python keywords in atest/library/ and Browser/keywords/ can and should have docstrings. These are discoverable via libdoc and IDE tooling.

def assert_passed_duration(start_time: datetime, max_duration_ms: int, delta_ms: int = 300) -> None:
    """Assert that the time elapsed since start_time does not exceed max_duration_ms + delta_ms."""
    ...

Complex logic belongs in library keywords

If a keyword requires nested branching, or loops, those belong to Python library. Complex data transformation, or non-trivial orchestration, should be also implemented as a Python keyword in atest/library/ — not as a user keyword in a .robot file. Robot Framework syntax is not suited for complex logic.

Good — complex assertion delegated to Python

*** Test Cases ***
Scope Settings Are Restored After Test
    Log All Scopes    exp_timeout=10    exp_strict_mode=True
# atest/library/scope_logger.py
def log_all_scopes(exp_timeout: float, exp_strict_mode: bool) -> None:
    b: Browser = BuiltIn().get_library_instance("Browser")
    timeout = b.scope_stack["timeout"].get()
    assert timeout == exp_timeout, f"timeout {timeout} != {exp_timeout}"

Bad — logic squeezed into user keyword

*** Keywords ***
Verify Scope Timeout
    [Arguments]    ${expected}
    ${actual}=    Evaluate    ...complex expression...
    Run Keyword If    '${actual}' != '${expected}'    Fail    ...

Library keywords must have type hints

All Python keyword functions in atest/library/ must have type annotations on parameters and return values.

Good

def start_test_server() -> str:
    ...

def assert_passed_duration(start_time: datetime, max_duration_ms: int, delta_ms: int = 300) -> None:
    ...

Bad

def start_test_server():
    ...

def assert_passed_duration(start_time, max_duration_ms, delta_ms=300):
    ...

Avoid deeply nested user keywords

The Browser library already provides rich, high-level keywords. Avoid building deep stacks of user keywords that wrap other user keywords. Test-suite-level keywords (in a *** Keywords *** section of a .robot file) are fine for encapsulating setup/teardown or repeated actions within that suite.

Good — one thin suite-level keyword delegates directly to Browser keywords

*** Keywords ***
Open Browser To Login Page
    New Browser    ${BROWSER}    headless=${HEADLESS}
    New Page    ${LOGIN_URL}

Bad — unnecessary nesting: suite keyword → user keyword → user keyword

*** Keywords ***
Open Browser To Login Page
    Open Browser With Settings
    Navigate To Login

Open Browser With Settings
    New Browser    ${BROWSER}    headless=${HEADLESS}

Navigate To Login
    Go To Login Page

Go To Login Page
    New Page    ${LOGIN_URL}

File locations

Content Location
Acceptance test files atest/test/<suite>/
Shared library keywords (Python) atest/library/
Shared resource files atest/test/keywords.resource, atest/test/variables.resource

Running acceptance tests

inv atest

Lint after changes:

inv lint-robot
Install via CLI
npx skills add https://github.com/MarketSquare/robotframework-browser --skill write-robot-tests
Repository Details
star Stars 651
call_split Forks 143
navigation Branch main
article Path SKILL.md
More from Creator
MarketSquare
MarketSquare Explore all skills →