Skip to content

JavaScript Executors

Eduard Dik edited this page Feb 4, 2026 · 2 revisions

JavaScript Executors Overview

In modern web automation, standard Selenium commands are often not enough to handle complex tasks like precise visibility checks, finding random clickable points, or analyzing the viewport.

The javascript executor package provides a unified layer for running pre-written, highly optimized JavaScript snippets in the browser, regardless of whether you are using a synchronous or asynchronous (Trio) driver.


Modular Architecture

The package is built using an abstraction layer to ensure that the developer interface remains identical across architectures.

  • AbstractJSExecutor: Defines the required methods (the "contract") for all JS executors.
  • UnifiedJSExecutor: Contains the internal implementation logic. It bridges Python calls to actual JavaScript execution.
  • Implementation Classes:
    • sync.JSExecutor: Executes scripts immediately.
    • trio_threads.JSExecutor: Executes scripts in worker threads to prevent blocking the async loop.
    • trio_bidi.JSExecutor: Executes via TrioBiDiMixin, routing calls through the BiDi Mapping layer (mapping to script.callFunction or script.evaluate via the connection pool).

The Internal Script Library

Instead of hardcoding JavaScript as long strings inside Python files, osn-selenium stores scripts as individual .js files in the osn_seelnium/javascript/scripts/ directory. This ensures the same script is guaranteed to run in Sync, Trio, and BiDi modes.

Automated Loading

The function get_js_scripts() automatically reads all files from the osn_seelnium/javascript/scripts folder and maps them to the JS_Scripts model. This allows for:

  • Better Syntax Highlighting: Writing pure JS files is easier and less error-prone.
  • Caching: Scripts are loaded and validated once at runtime.
  • Consistency: The same script is guaranteed to run in both Sync and Trio modes.

High-Level Utility Methods

The JS executor provides several powerful methods out of the box that extend beyond standard Selenium capabilities:

Method Description
check_element_in_viewport Returns True only if the element is currently visible within the user's viewable area.
get_random_element_point Finds a random $(x, y)$ coordinate inside an element's visible shape. Essential for human-like clicking.
get_viewport_rect Returns the exact dimensions and scroll offsets of the browser viewport.
get_element_css_style Retrieves all computed CSS properties for an element at once.
stop_window_loading Immediately stops the browser from loading further resources (useful for speed).
start_fingerprint_detection Injects the stealth logic and hooks into the browser APIs.

Usage Example

Access the executor through the javascript property of your driver.

# Synchronous Example
style = driver.javascript.get_element_css_style(element)
print(style['background-color'])

# Asynchronous Example (Trio)
is_visible = await driver.javascript.check_element_in_viewport(element)
if is_visible:
    # Get a random point within the element for a natural click
    point = await driver.javascript.get_random_element_point(element)
    await driver.action_chains().hm_move(start_point, point).click().perform()

The JS Bridge & Data Conversion

Under the hood, the library uses a specialized bridge to handle data transfer between Python and the browser's V8 engine:

convert_to_js_value

A utility that translates Python data structures into their JavaScript equivalents:

  • None $\rightarrow$ null
  • True/False $\rightarrow$ true/false
  • dict $\rightarrow$ Object
  • list/tuple $\rightarrow$ Array

get_js_executor_bridge

This bridge ensures that when a script returns a DOM element, it is automatically wrapped in the framework's own WebElement class (Sync or TrioThread), maintaining architectural integrity.

Clone this wiki locally