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 Initialize Js Extension

From Leeroopedia

Initialize JavaScript Extension API

Type

API Doc

Source

Browser/base/librarycomponent.py, lines 218-224

APIs

initialize_js_extension

def initialize_js_extension(
    self, js_extension_path: Path | str
) -> Response.Keywords:
    return self.library.init_js_extension(js_extension_path=js_extension_path)

Parameters:

Parameter Type Description
js_extension_path str Absolute or relative path to a JavaScript file containing exported async functions. The path is resolved to an absolute path before being sent to the Node.js process.

Returns: Response.Keywords

The return value is a protobuf message containing three repeated fields:

Field Type Description
.keywords repeated string Names of the exported JavaScript functions discovered in the file.
.keywordArguments repeated string Comma-separated argument names (including defaults) for each function.
.keywordDocumentations repeated string Documentation strings for each function (if provided in the JS source).

Underlying Implementation:

The method delegates to Browser.init_js_extension() at Browser/browser.py lines 1011-1017:

def init_js_extension(self, js_extension_path: Path | str) -> Response.Keywords:
    with self.playwright.grpc_channel() as stub:
        return stub.InitializeExtension(
            Request().FilePath(
                path=str(Path(js_extension_path).resolve().absolute())
            )
        )

This sends an InitializeExtension gRPC request with the resolved absolute file path. The Node.js process loads the JavaScript module, inspects its exports, and returns metadata about the discovered functions.

call_js_keyword

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

Parameters:

Parameter Type Description
keyword_name str The name of the JavaScript function to call. Must match an exported function name from a previously loaded extension.
**args Any Keyword arguments to pass to the JavaScript function. Argument names matching reserved names (page, logger, playwright, context, browser) are automatically replaced with "RESERVED" and injected on the Node.js side.

Returns: Any

The return value is the deserialized JSON response from the JavaScript function. Returns None if the JavaScript function returns undefined or produces an empty response.

Underlying Implementation:

The method delegates to Browser.call_js_keyword() at Browser/browser.py lines 1086-1109:

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

The method:

  1. Builds an argument list, replacing reserved parameter names with "RESERVED"
  2. Serializes the arguments as JSON
  3. Sends a CallExtensionKeyword gRPC request
  4. Iterates over the streaming response, logging each message
  5. Parses and returns the final JSON response

Usage: Called from Plugin __init__

The typical usage pattern is to call initialize_js_extension during plugin construction and then use call_js_keyword in keyword methods:

from pathlib import Path
from robot.api.deco import keyword
from Browser import Browser
from Browser.base.librarycomponent import LibraryComponent


class MyPlugin(LibraryComponent):
    def __init__(self, library: Browser) -> None:
        super().__init__(library)
        # Load the JavaScript extension during initialization
        response = self.initialize_js_extension(
            Path(__file__).parent.resolve() / "my_extension.js"
        )
        # Optionally inspect what was loaded
        for kw_name in response.keywords:
            print(f"Loaded JS keyword: {kw_name}")

    @keyword
    def my_custom_scroll(self, x: int, y: int):
        """Scrolls the page using a custom JavaScript function."""
        return self.call_js_keyword("customScroll", x=x, y=y)

JavaScript Extension File Format

The JavaScript file must export functions using CommonJS or ES module syntax:

// my_extension.js
async function customScroll(x, y, logger, page) {
    logger(`Scrolling to ${x}, ${y}`);
    await page.mouse.wheel(x, y);
    return await page.evaluate("document.scrollingElement.scrollTop");
}

exports.__esModule = true;
exports.customScroll = customScroll;

Key rules for JavaScript extensions:

  • Functions should be async (they run in an async context)
  • Reserved parameter names (page, logger, playwright, context, browser) receive live Playwright objects
  • Non-reserved parameters receive values passed from the Python call_js_keyword call
  • Return values are serialized to JSON and sent back to Python
  • Use logger() to emit log messages visible in Robot Framework reports

Example from the Test Suite

From atest/test/09_Plugins/jsplugin.js:

async function mouseWheel(x, y, logger, page) {
    logger(`Mouse wheel at ${x}, ${y}`);
    await page.mouse.wheel(x, y);
    logger("Returning a funny string");
    return await page.evaluate("document.scrollingElement.scrollTop");
}

exports.__esModule = true;
exports.mouseWheel = mouseWheel;

Called from atest/test/09_Plugins/ExamplePlugin.py:

@keyword
def mouse_wheel(self, x: int, y: int):
    """This keyword calls a custom javascript keyword from the file jsplugin.js."""
    return self.call_js_keyword("mouseWheel", y=y, x=x)

Error Handling

  • If the JavaScript file path does not exist or cannot be loaded, the gRPC call raises an error during initialize_js_extension
  • If a called keyword name does not match any loaded function, CallExtensionKeyword raises a gRPC error
  • JavaScript runtime exceptions are captured and propagated back as gRPC errors

Related

Page Connections

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