Principle:MarketSquare Robotframework browser Keyword Method Implementation
Keyword Method Implementation
Overview
In robotframework-browser, test automation keywords are defined as decorated Python methods on classes that inherit from LibraryComponent. The @keyword decorator marks a method as a Robot Framework keyword, making it discoverable by the framework's dynamic library protocol. This pattern applies identically to both built-in keyword modules and plugin classes.
Core Concept: Methods as Keywords
Robot Framework's dynamic library API allows a library to report its keywords at runtime rather than relying on static introspection. The DynamicCore base class (from robotlibcore) scans all registered components for methods decorated with @keyword and exposes them to Robot Framework.
A keyword method is simply a Python method with:
- A
@keyworddecorator (from eitherrobot.api.decoorBrowser.utils) - A descriptive docstring (used for keyword documentation)
- Type-annotated parameters (used for automatic type conversion)
- A return value (available in Robot Framework as the keyword's return value)
from robot.api.deco import keyword
class MyPlugin(LibraryComponent):
@keyword
def my_keyword(self, selector: str, timeout: timedelta = None) -> str:
"""Returns the text content of the element matching the selector."""
resolved = self.resolve_selector(selector)
# ... implementation ...
return result
The @keyword Decorator
The decorator serves multiple purposes:
| Attribute | Purpose | Example |
|---|---|---|
name |
Override the keyword name (default: derived from method name) | @keyword(name="Get Element Text")
|
tags |
Attach tags for filtering and categorization | @keyword(tags=("Getter", "Element"))
|
types |
Override automatic type detection | @keyword(types={"timeout": timedelta})
|
The robotframework-browser library provides its own keyword function in Browser/utils/misc.py that is a lightweight wrapper setting robot_name, robot_tags, and robot_types attributes on the decorated function. Both the standard robot.api.deco.keyword and the library's custom Browser.utils.keyword work for plugins.
Three Interaction Patterns
Keyword methods in plugins can interact with the browser through three distinct patterns:
Pattern 1: Direct gRPC Communication
The plugin opens a gRPC channel to the Node.js Playwright process and invokes a Playwright operation directly via protobuf messages:
@keyword
def new_plugin_cookie_keyword(self) -> dict:
"""Uses gRPC to directly call the Node.js side."""
with self.playwright.grpc_channel() as stub:
response = stub.GetCookies(Request().Empty())
cookies = json.loads(response.json)
return {"name": cookies[0]["name"], "value": cookies[0]["value"]}
This pattern gives full control over the Playwright protocol but requires knowledge of the gRPC service definition and protobuf message types.
Pattern 2: Calling Existing Library Keywords
The plugin calls methods on self.library, which is the fully initialized Browser instance. This allows reuse of existing keyword logic:
@keyword
def get_location_object(self) -> dict:
"""Calls the existing Evaluate Javascript keyword."""
location_dict = self.library.evaluate_javascript(None, "window.location")
return DotDict(location_dict)
This is the simplest pattern -- it composes higher-level behavior from existing keywords without needing to understand gRPC or protobuf details.
Pattern 3: Calling JavaScript Extensions
The plugin loads a JavaScript file and calls its exported functions. The JavaScript runs in Node.js with access to Playwright objects:
# In __init__:
self.initialize_js_extension(Path(__file__).parent / "myplugin.js")
# As a keyword:
@keyword
def mouse_wheel(self, x: int, y: int):
"""Calls a custom JavaScript keyword."""
return self.call_js_keyword("mouseWheel", y=y, x=x)
This pattern bridges Python and JavaScript, enabling direct DOM manipulation or access to Playwright APIs not exposed through gRPC.
Method Naming and Keyword Names
By default, Robot Framework derives the keyword name from the Python method name using these rules:
- Underscores become spaces:
get_location_objectbecomesGet Location Object - The name is case-insensitive in Robot Framework test files
The name parameter of the @keyword decorator overrides this default. For plugins, using explicit names is recommended when the desired keyword name does not follow simple underscore-to-space conversion.
Type Annotations and Automatic Conversion
Robot Framework performs automatic type conversion based on Python type annotations. When a keyword parameter is annotated with a type, Robot Framework converts the string argument from the test file to that type:
| Annotation | Input (string) | Converted Value |
|---|---|---|
int |
"42" |
42
|
bool |
"true" |
True
|
timedelta |
"5s" |
timedelta(seconds=5)
|
Enum subclass |
"value_name" |
EnumClass.value_name
|
This is particularly important for Browser library keywords that accept timedelta for timeouts, enum types for selectors and states, and complex types like dict for configuration objects.
Automatic Plugin Tagging
All keywords that originate from a plugin class are automatically tagged with "Plugin". This is handled by the Browser.get_keyword_tags() method at Browser/browser.py lines 1301-1305:
def get_keyword_tags(self, name: str) -> list:
tags = list(DynamicCore.get_keyword_tags(self, name))
if name in self._plugin_keywords:
tags.append("Plugin")
return tags
This means plugin authors do not need to manually add the "Plugin" tag -- it is injected automatically by the library.
Docstrings as Documentation
The docstring of a keyword method becomes the keyword's documentation in Robot Framework's libdoc output and in IDE autocompletion. Use reStructuredText or plain text formatting in docstrings. The first line should be a concise summary, with additional details in subsequent paragraphs.
Domains
Implemented By
Related
- MarketSquare_Robotframework_browser_Keyword_Decorator_Pattern -- Implementation details of the
@keyworddecorator - MarketSquare_Robotframework_browser_Plugin_Architecture -- The plugin architecture that hosts keyword methods
- MarketSquare_Robotframework_browser_JavaScript_Extension_Integration -- Pattern 3 in depth