Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:MarketSquare Robotframework browser Call Js Keyword

From Leeroopedia

Document Type

API Doc -- Documents the Browser.call_js_keyword method, which provides a programmatic Python API for invoking JavaScript extension functions via the gRPC bridge without relying on auto-generated keyword wrappers.

API Summary

The call_js_keyword method allows Python code (plugins, other library components, or direct programmatic use) to call any registered JavaScript extension function by name, passing keyword arguments that are serialized and transmitted to the Node.js side via gRPC.

Source Reference

File Lines Description
Browser/browser.py L1086-1110 call_js_keyword method definition

API: call_js_keyword

Signature

def call_js_keyword(self, keyword_name: str, **args) -> Any:

Parameters

Parameter Type Description
keyword_name str The name of the JavaScript function to call (as it was exported in the module)
**args keyword arguments Named arguments to pass to the JavaScript function; reserved names are automatically handled

Returns

  • Any -- The deserialized return value from the JavaScript function, or None if the function returns no value

Source Code

def call_js_keyword(self, keyword_name: str, **args) -> Any:
    reserved = {
        "logger": "RESERVED",
        "playwright": "RESERVED",
        "page": "RESERVED",
        "context": "RESERVED",
        "browser": "RESERVED",
    }
    _args_browser_internal = {
        "arguments": [
            (arg_name, reserved.get(arg_name, value))
            for arg_name, value in args.items()
        ]
    }
    with self.playwright.grpc_channel() as stub:
        responses = stub.CallExtensionKeyword(
            Request().KeywordCall(
                name=keyword_name, arguments=json.dumps(_args_browser_internal)
            )
        )
        for response in responses:
            logger.info(response.log)
        if response.json == "":
            return None
        return json.loads(response.json)

Behavior

1. Reserved Parameter Handling

The method defines a dictionary of reserved parameter names and their sentinel values:

reserved = {
    "logger": "RESERVED",
    "playwright": "RESERVED",
    "page": "RESERVED",
    "context": "RESERVED",
    "browser": "RESERVED",
}

When building the argument list, each argument name is checked against this dictionary. If the name matches a reserved name, the value "RESERVED" is substituted regardless of what the caller provided. Otherwise, the caller's value is used as-is.

This ensures that even if a caller inadvertently passes values for reserved parameters, the Node.js side will still inject the correct live Playwright objects.

2. Argument Serialization

Arguments are structured as a list of (name, value) tuples inside a dictionary:

_args_browser_internal = {
    "arguments": [
        (arg_name, reserved.get(arg_name, value))
        for arg_name, value in args.items()
    ]
}

This structure is serialized to JSON with json.dumps() and passed as the arguments field of a Request().KeywordCall protobuf message.

3. gRPC Call

with self.playwright.grpc_channel() as stub:
    responses = stub.CallExtensionKeyword(
        Request().KeywordCall(
            name=keyword_name, arguments=json.dumps(_args_browser_internal)
        )
    )

The method opens a gRPC channel to the Node.js Playwright wrapper and calls the CallExtensionKeyword RPC method. This returns a stream of response messages.

4. Response Processing

for response in responses:
    logger.info(response.log)
if response.json == "":
    return None
return json.loads(response.json)

Each response in the stream may contain a log message (from calls to the logger function on the JS side), which is forwarded to Python's logger.info().

After iterating through all responses, the final response's json field is examined:

  • If empty (""): the method returns None
  • Otherwise: the JSON string is parsed with json.loads() and the resulting Python object is returned

Comparison with Auto-Generated Wrappers

The auto-generated keyword wrappers (created by _jskeyword_call) and call_js_keyword use the same underlying mechanism:

Aspect Auto-Generated Wrapper call_js_keyword
Invocation Via Robot Framework keyword resolution Direct Python method call
Arguments Positional/keyword with Python defaults Keyword-only (**args)
Reserved handling Hardcoded "RESERVED" in generated code Dynamic lookup in reserved dict
gRPC call stub.CallExtensionKeyword stub.CallExtensionKeyword
Return handling json.loads or return json.loads or None

The key difference is that call_js_keyword is a single generic entry point, while the auto-generated wrappers provide type-specific signatures matching each JavaScript function.

Usage Example

From Python code within a Browser library plugin or component:

# Call a JS extension function named "withDefaultValue"
result = self.library.call_js_keyword("withDefaultValue", a="custom_value")

# Call with reserved parameters (they will be auto-replaced with "RESERVED")
result = self.library.call_js_keyword(
    "myNewStyleFunkyKeyword",
    selector="#heading",
    page="ignored",   # will be replaced with "RESERVED"
    logger="ignored",  # will be replaced with "RESERVED"
)

Related

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment