Principle:MarketSquare Robotframework browser Extension Import and Registration
Overview
The robotframework-browser library supports dynamically loading JavaScript modules and registering their exported functions as Robot Framework keywords. This process occurs at library import time -- when a test suite's *** Settings *** section instantiates the Browser library with a jsextension parameter. The library orchestrates a multi-step pipeline that spans Python and Node.js to transform JavaScript functions into callable keywords.
Core Concept
The extension import and registration process bridges two language runtimes. The high-level flow is:
- Path resolution: The
jsextensionparameter (a file path or comma-separated list of paths) is parsed and resolved to absolute paths - Module introspection via gRPC: Each module is sent to the Node.js gRPC server, which uses
require()to load it, then inspects every exported function's name, parameters, default values, and documentation - Response parsing: The gRPC response contains lists of keyword names, argument specifications, and documentation strings
- Dynamic Python method generation: For each discovered function, a Python method is generated at runtime using
exec()and bound to aLibraryComponentinstance - Registration: The
LibraryComponentis added to the library's component list, making all its methods available as Robot Framework keywords through the DynamicCore
JavaScript Module Introspection
When the Node.js gRPC server receives an InitializeExtension request, it:
- Loads the module using
require() - Iterates over the module's
exportsobject - For each exported function, extracts:
- Function name -- The property name on the exports object
- Parameter list -- Parsed from the function's
.toString()representation - Default values -- Extracted from the function signature
- Documentation -- Read from the optional
.rfdocproperty
The results are packaged into a Response.Keywords protobuf message containing parallel arrays: keywords, keywordArguments, and keywordDocumentations.
Dynamic Python Method Generation
The Python side generates wrapper methods using a code template that is passed to exec(). For each JavaScript function, a Python method is created that:
- Accepts the same user-facing arguments (with JS defaults mapped to Python equivalents)
- Marks reserved parameters (page, context, browser, logger, playwright) with the sentinel value
"RESERVED" - Serializes all arguments as JSON
- Calls
stub.CallExtensionKeywordvia the gRPC channel - Deserializes the JSON response
The generated method is then bound to a LibraryComponent instance using types.MethodType, making it a proper instance method that the DynamicCore can discover and expose.
Error Handling
If the generated Python code for a keyword has a syntax error (e.g., because the JavaScript function used self as a parameter name, which conflicts with Python's method signature), a DataError is raised during library initialization with a descriptive message.
Multiple Extensions
The jsextension parameter supports multiple modules:
- As a comma-separated string:
jsextension="path/to/a.js,path/to/b.js" - As a list:
jsextension=["path/to/a.js", "path/to/b.js"]
Each module produces its own LibraryComponent, and all components are appended to the library's component list.
Domains
- Dynamic_Loading -- Modules are loaded at runtime based on configuration parameters
- Code_Generation -- Python wrapper methods are generated dynamically using
exec()
Implemented By
Related Topics
- MarketSquare_Robotframework_browser_Create_Lib_Component_From_Jsextension -- Implementation details of the registration APIs
- MarketSquare_Robotframework_browser_JavaScript_Module_Authoring -- Rules for writing extension modules
- MarketSquare_Robotframework_browser_Custom_Keyword_Invocation -- How registered keywords are called at runtime
- MarketSquare_Robotframework_browser_Js_Module_Exports_Pattern -- The CommonJS export pattern expected by the loader