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.

Principle:MarketSquare Robotframework browser Plugin Architecture

From Leeroopedia

Plugin Architecture

Overview

The robotframework-browser library implements a plugin architecture that allows developers to extend the library's keyword set without modifying its core source code. Plugins are Python classes that inherit from the LibraryComponent base class, gaining access to the parent library's internal APIs including gRPC communication channels, configuration settings, context caches, and utility methods.

This architecture follows the Open/Closed Principle: the library is open for extension through plugins but closed for modification of its core behavior.

Core Concept: Extending Through Inheritance

The plugin architecture rests on a single design decision: every functional component of the Browser library -- whether built-in or user-provided -- inherits from the same base class, LibraryComponent. This base class acts as a facade that exposes a curated subset of the main Browser library's internals.

When a plugin class inherits from LibraryComponent, it receives:

  • The library instance itself (self.library) -- the fully initialized Browser object
  • The Playwright gRPC channel (self.playwright) -- for direct communication with the Node.js Playwright process
  • Configuration stacks (self.timeout, self.strict_mode, self.selector_prefix) -- scope-aware settings
  • Output paths (self.outputdir, self.browser_output) -- for file generation
  • Context cache (self.context_cache) -- for accessing browser/page state
  • Utility methods (self.resolve_selector(), self.get_timeout()) -- shared logic

Dependency Injection

Plugin classes use constructor-based dependency injection. The plugin constructor receives the Browser library instance as its sole required argument:

class MyPlugin(LibraryComponent):
    def __init__(self, library: Browser) -> None:
        super().__init__(library)
        # Plugin-specific initialization here

The PluginParser from robotlibcore handles the instantiation, automatically passing the library instance to each plugin constructor. This means plugin authors never need to construct their plugins manually -- the library's import mechanism does it.

Separation of Concerns

The architecture enforces a clean separation:

Concern Location Responsibility
Core keywords Browser/keywords/ modules Standard browser automation operations (click, type, navigate, etc.)
Plugin keywords External plugin classes Domain-specific or project-specific keywords
Base infrastructure LibraryComponent Shared access to library internals
Plugin loading PluginParser + DynamicCore Discovery, instantiation, and keyword registration

Built-in keyword modules (like Interaction, Getters, Network) and plugins both inherit from LibraryComponent. From the Robot Framework runtime's perspective, there is no distinction between a built-in keyword and a plugin keyword -- they are all methods on components registered with the DynamicCore.

Plugin Capabilities

A plugin can exercise three distinct interaction patterns:

1. Direct gRPC Communication

Plugins can open a gRPC channel to the Node.js process and call Playwright operations directly:

with self.playwright.grpc_channel() as stub:
    response = stub.GetCookies(Request().Empty())

2. Calling Existing Library Keywords

Plugins can invoke any keyword already defined on the Browser library by calling methods on self.library:

location = self.library.evaluate_javascript(None, "window.location")

3. JavaScript Extension Integration

Plugins can load custom JavaScript files that run in the Node.js context and call them as keywords:

self.initialize_js_extension(path_to_js_file)
result = self.call_js_keyword("myJsFunction", arg1=value1)

Automatic Tagging

All keywords originating from plugins are automatically tagged with the "Plugin" tag. This happens in the Browser.get_keyword_tags() method, which checks whether a keyword name appears in the _plugin_keywords list. This tagging allows test suites to:

  • Filter test execution by plugin keywords
  • Identify in documentation which keywords come from plugins
  • Apply tag-based listeners or hooks

Architecture Diagram

+---------------------------+
|     Robot Framework        |
|     Test Suite             |
+------------+--------------+
             |
             v
+---------------------------+
|     Browser (DynamicCore)  |
|  - Built-in keyword modules|
|  - Plugin keyword modules  |
+-----+----------+----------+
      |          |
      v          v
+----------+ +------------+
|LibraryComponent|LibraryComponent|
| (Built-in)|  (Plugin)    |
+-----+-----+------+------+
      |             |
      v             v
+---------------------------+
|   Playwright gRPC Channel  |
|   (Node.js Process)        |
+---------------------------+

Design Rationale

This architecture was chosen because:

  • Composability: Multiple plugins can be loaded simultaneously, each contributing keywords without conflict
  • Encapsulation: Plugins access library internals through a controlled interface (LibraryComponent), not by reaching into private implementation details
  • Familiarity: Plugin authors use the same patterns as the library's own keyword modules, reducing the learning curve
  • Runtime flexibility: Plugins are specified at library import time, allowing different test suites to load different plugin combinations

Domains

Implemented By

Related

Page Connections

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