Galaxy Selenium interaction framework
Project description
Galaxy Browser Automation Framework
Overview
This package provides a browser automation framework for Galaxy with:
Multi-backend support: Selenium and Playwright backends with a unified API
Protocol-based architecture: Clean separation between Galaxy logic and browser interaction
Comprehensive testing: Full unit test coverage for both backends
CLI tooling: Utilities for building command-line automation scripts
Type safety: Full type hints with mypy validation
Architecture
Core Interfaces
The framework is built around two main protocol interfaces:
- HasDriverProtocol (has_driver_protocol.py)
Defines ~60+ browser automation operations including:
Element finding (by ID, selector, XPath, etc.)
Wait methods (visible, clickable, absent, etc.)
Interactions (click, hover, drag-and-drop, keyboard input)
Navigation (URLs, frames, alerts)
JavaScript execution
Accessibility testing (axe-core integration)
- WebElementProtocol (web_element_protocol.py)
Defines the common element API:
text, click(), send_keys(), clear()
get_attribute(), is_displayed(), is_enabled()
find_element(), find_elements()
value_of_css_property() for CSS introspection
Architecture Diagram
┌─────────────────────────────────────────────────────┐
│ Galaxy Application Layer │
│ │
│ NavigatesGalaxy (navigates_galaxy.py) │
│ - Galaxy-specific page objects │
│ - Workflow interactions │
│ - History management │
│ - Tool execution │
└────────────────┬────────────────────────────────────┘
│ extends
↓
┌─────────────────────────────────────────────────────┐
│ Browser Automation Abstraction Layer │
│ │
│ HasDriverProxy (has_driver_proxy.py) │
│ - Delegates to HasDriverProtocol implementation │
│ - Runtime backend selection via composition │
└────────────────┬────────────────────────────────────┘
│ uses
↓
┌──────────────────────────────────┬──────────────────┐
│ HasDriverProtocol │ │
│ (has_driver_protocol.py) │ │
│ - Abstract interface │ │
│ - ~60+ operations │ │
└──────────────┬───────────────────┴──────────────────┘
│ implemented by
┌─────────┴──────────┐
↓ ↓
┌─────────────┐ ┌──────────────────┐
│ HasDriver │ │ HasPlaywright │
│ │ │ Driver │
│ Selenium │ │ │
│ backend │ │ Playwright │
│ │ │ backend │
└──────┬──────┘ └────────┬─────────┘
│ │
↓ ↓
┌─────────────┐ ┌──────────────────┐
│ WebElement │ │ PlaywrightElement│
│ (Selenium) │ │ (wrapper) │
│ │ │ │
│ implements │ │ implements │
│ protocol │ │ protocol │
└─────────────┘ └──────────────────┘
│ │
└──────────┬─────────┘
↓
WebElementProtocol
(web_element_protocol.py)
Implementations
- Selenium Backend (has_driver.py)
Uses Selenium WebDriver
Direct WebElement support (implements protocol natively)
Mature, widely-used automation framework
Supports remote execution (Selenium Grid)
- Playwright Backend (has_playwright_driver.py)
Uses Playwright sync API
PlaywrightElement wrapper (adapts ElementHandle to protocol)
Modern automation with auto-waiting
Fast and reliable for modern web apps
Local execution only (no remote support)
Both implementations:
Share identical test suite (150+ parametrized tests)
Provide consistent API via protocols
Support headless and headed modes
Include full type hints
Separation of Concerns
Application Logic │ Browser Automation
(Galaxy-specific) │ (Generic, reusable)
─────────────────────────────────────────────────
navigates_galaxy.py │ has_driver_protocol.py
- Galaxy UI interactions │ - Abstract interface
- Workflow automation │ - Element finding
- History operations │ - Wait strategies
- Tool wrappers │ - Interactions
│
smart_components.py │ has_driver.py
- Galaxy component │ - Selenium impl
wrappers │
- Page object patterns │ has_playwright_driver.py
│ - Playwright impl
│
│ web_element_protocol.py
│ - Element interface
Key Principle: Galaxy-specific logic lives in navigates_galaxy.py and extends the generic browser automation protocols. This separation allows:
Testing browser automation independently
Reusing automation primitives across projects
Switching backends without changing application code
Clear boundaries between concerns
Testing
The framework includes comprehensive unit tests in test/unit/selenium/test_has_driver.py:
Parametrized tests: Every test runs against Selenium, Playwright, and proxied backends
150+ test cases covering all protocol methods
Test fixtures: Reusable HTML pages served via local HTTP server
Scope-optimized: Session-scoped server, function-scoped drivers
Run tests from the package directory:
# All tests uv run pytest tests/seleniumtests/test_has_driver.py -v # Specific test class uv run pytest tests/seleniumtests/test_has_driver.py::TestElementFinding -v # Type checking make mypy
Building CLI Tools
The cli.py module provides infrastructure for building command-line automation tools.
Core Components
- add_selenium_arguments(parser)
Adds standard CLI arguments:
--selenium-browser: Browser choice (chrome, firefox, auto)
--selenium-headless: Headless mode flag
--backend: Backend selection (selenium, playwright)
--galaxy_url: Target Galaxy instance URL
--selenium-remote: Remote execution (Selenium only)
- DriverWrapper
Adapts argparse args to a NavigatesGalaxy instance:
Handles backend selection
Manages virtual display (for headless Selenium)
Provides Galaxy navigation utilities
Cleanup via finish() method
Example: dump_tour.py
The scripts/dump_tour.py script demonstrates CLI tool development:
#!/usr/bin/env python
import argparse
from galaxy.selenium import cli
def main(argv=None):
args = _arg_parser().parse_args(argv)
driver_wrapper = cli.DriverWrapper(args)
# Use driver_wrapper for automation
callback = DumpTourCallback(driver_wrapper, args.output)
driver_wrapper.run_tour(args.tour, tour_callback=callback)
def _arg_parser():
parser = argparse.ArgumentParser(description="Walk a Galaxy tour")
parser.add_argument("tour", help="tour to walk")
parser.add_argument("-o", "--output", help="screenshot output dir")
parser = cli.add_selenium_arguments(parser) # Add standard args
return parser
class DumpTourCallback:
def handle_step(self, step, step_index: int):
self.driver_wrapper.save_screenshot(f"{output}/{step_index}.png")
Usage:
# With Selenium backend python dump_tour.py my_tour.yaml --backend selenium --selenium-headless # With Playwright backend python dump_tour.py my_tour.yaml --backend playwright --galaxy_url http://localhost:8080
Building Your Own CLI Tool
Import the CLI utilities:
from galaxy.selenium import cli
Create argument parser:
parser = argparse.ArgumentParser(description="My automation tool") parser.add_argument("--my-option", help="Custom option") parser = cli.add_selenium_arguments(parser) # Add standard argsCreate DriverWrapper:
args = parser.parse_args() driver_wrapper = cli.DriverWrapper(args)
Use NavigatesGalaxy API:
# driver_wrapper has all NavigatesGalaxy methods driver_wrapper.navigate_to(url) driver_wrapper.click_selector("#my-button") driver_wrapper.wait_for_selector_visible(".result")Clean up:
driver_wrapper.finish() # Quits driver and stops virtual display
Development
Package Structure
packages/selenium/
├── galaxy/selenium/ # Symlink to lib/galaxy/selenium/
├── tests/seleniumtests/ # Symlink to test/unit/selenium/
├── README.rst # This file
└── pyproject.toml
lib/galaxy/selenium/ # Actual source code
├── has_driver_protocol.py # Protocol interface
├── has_driver.py # Selenium implementation
├── has_playwright_driver.py # Playwright implementation
├── web_element_protocol.py # Element interface
├── playwright_element.py # Element wrapper
├── navigates_galaxy.py # Galaxy-specific logic
├── smart_components.py # Component wrappers
├── cli.py # CLI utilities
└── scripts/
└── dump_tour.py # Example CLI tool
test/unit/selenium/ # Actual tests
├── conftest.py # Pytest fixtures
├── test_has_driver.py # Main test suite
└── fixtures/ # HTML test pages
Running Commands
Always use uv run from the package directory:
# Run tests uv run pytest tests/seleniumtests/test_has_driver.py -v # Type checking make mypy # Linting uv run ruff check .
Adding New Low-Level Browser Operations
Low-level operations are generic browser automation primitives that work with both backends.
Manual Process:
Add to protocol (has_driver_protocol.py):
@abstractmethod def my_new_operation(self, param: str) -> bool: """Do something useful.""" ...Implement in Selenium (has_driver.py):
def my_new_operation(self, param: str) -> bool: # Selenium implementation return self.driver.do_something(param)Implement in Playwright (has_playwright_driver.py):
def my_new_operation(self, param: str) -> bool: # Playwright implementation return self.page.do_something(param)Update proxy (has_driver_proxy.py):
def my_new_operation(self, param: str) -> bool: """Do something useful.""" return self._driver_impl.my_new_operation(param)Add tests (test_has_driver.py):
def test_my_new_operation(self, has_driver_instance, base_url): """Test new operation works on both backends.""" has_driver_instance.navigate_to(f"{base_url}/test.html") result = has_driver_instance.my_new_operation("test") assert result is True
Automated Process:
Use the /add-browser-operation slash command to automate these steps:
/add-browser-operation scroll element to center of viewport
This command will generate all the necessary code across all files and create tests.
Adding New Smart Component Operations
Smart component operations are higher-level conveniences that may require adding low-level operations first. These operations make Galaxy components more ergonomic to use in tests.
When to Add Smart Operations:
When you find yourself repeating a pattern of low-level operations
When Galaxy-specific UI patterns need convenient wrappers
When you want to express test intent more clearly
Process:
Determine if low-level support exists:
Check if the required browser operation exists in HasDriverProtocol. If not, add it first using the process above (or /add-browser-operation).
Add to SmartTarget (smart_components.py):
Add a method to the SmartTarget class:
def my_smart_operation(self, **kwds): """High-level operation description.""" # Delegate to has_driver protocol methods element = self._has_driver.wait_for_visible(self._target, **kwds) return self._has_driver.my_low_level_operation(element)Consider return value wrapping:
If your operation returns a Component or Target, wrap it:
def get_child_component(self, name: str): """Get a child component and wrap it smartly.""" child = self._target.get_child(name) return self._wrap(child) # Returns SmartTargetAdd tests (test/unit/selenium/test_smart_components.py):
Test with both backends using the has_driver_instance fixture:
def test_my_smart_operation(self, has_driver_instance, base_url): has_driver_instance.navigate_to(f"{base_url}/smart_components.html") # Use SmartComponent wrapping component = SmartComponent(MyComponent(), has_driver_instance) result = component.my_target.my_smart_operation() assert result is not None
Example: Adding a “wait_for_and_hover” operation
This demonstrates when you need to add a low-level operation first:
Check low-level support: hover() already exists in HasDriverProtocol ✓
Add to SmartTarget:
def wait_for_and_hover(self, **kwds): """Wait for element to be visible and hover over it.""" element = self._has_driver.wait_for_visible(self._target, **kwds) self._has_driver.hover(element) return elementUsage in tests:
# Before: Multiple steps element = driver.wait_for_visible(component.menu) driver.hover(element) # After: One expressive call component.menu.wait_for_and_hover()
Example: Adding operation requiring new low-level support
When the operation needs a new browser primitive:
Add low-level operation (see “Adding New Low-Level Browser Operations”):
Add scroll_to_center(element) to protocols and implementations
Add smart wrapper:
def wait_for_and_scroll_to_center(self, **kwds): """Wait for element and scroll it to viewport center.""" element = self._has_driver.wait_for_visible(self._target, **kwds) self._has_driver.scroll_to_center(element) return elementTest both levels:
Test low-level in test_has_driver.py
Test smart wrapper in test_smart_components.py
See Also
History
26.0.0 (2026-04-08)
Bug fixes
Attempt to fix transiently failing tests that click this tab. by @jmchilton in #21376
Fix selenium test test_rename_history by @davelopez in #21835
Enhancements
Replace Copy Dataset Mako with Vue Component by @guerler in #17507
Selenium test cases for IGV. by @jmchilton in #21034
Selenium test for #20886 (sharing private histories) by @jmchilton in #21040
Remove jquery from legacy onload helpers and Rule Builder by @guerler in #21063
Add Playwright Backend Support to Galaxy Browser Automation Framework by @jmchilton in #21102
Implement workflow completion monitoring with extensible hooks by @mvdbeek in #21532
25.1.2 (2026-03-09)
No recorded changes since last release
25.1.1 (2026-02-03)
Bug fixes
Usability fixes for sample sheet selection. by @jmchilton in #21503
25.1.0 (2025-12-12)
Bug fixes
Fix transient selenium error when adding collection input. by @jmchilton in #20460
Enhancements
Implement Sample Sheets by @jmchilton in #19305
Refactor Object Store Selection Modals UI by @itisAliRH in #19697
Selenium tests for various 24.2 features. by @jmchilton in #20215
Split Login and Register, enable OIDC Registration. by @uwwint in #20287
Add short term storage expiration indicator to history items by @davelopez in #20332
Type annotation fixes for mypy 1.16.0 by @nsoranzo in #20424
New History List Using GCard by @itisAliRH in #20744
25.0.4 (2025-11-18)
No recorded changes since last release
25.0.3 (2025-09-23)
No recorded changes since last release
25.0.2 (2025-08-13)
No recorded changes since last release
25.0.1 (2025-06-20)
No recorded changes since last release
25.0.0 (2025-06-18)
Bug fixes
Revise consistently failing edam tool panel view test. by @jmchilton in #19762
Fix workflow bookmark filtering by @davelopez in #20325
Enhancements
Workflow Editor Activity Bar by @ElectronicBlueberry in #18729
Workflow Run Form Enhancements by @ahmedhamidawan in #19294
Empower Users to Build More Kinds of Collections, More Intelligently by @jmchilton in #19377
Click to edit history name in HistoryPanel by @ahmedhamidawan in #19665
Fix Tours and add tooltips to history items by @guerler in #19734
Introduce reusable GCard component for unified card layout by @itisAliRH in #19785
Add history sharing and accessibility management view by @ahmedhamidawan in #19786
Replace backend-based page creation controller endpoint by @guerler in #19914
Implement dataset collection support in workflow landing requests by @mvdbeek in #20004
Add ZIP explorer to import individual files from local or remote ZIP archives by @davelopez in #20054
Client refactorings ahead of #19377. by @jmchilton in #20059
Revise transiently failing data source test. by @jmchilton in #20157
Visualization-First Display functionality by @dannon in #20190
24.2.4 (2025-06-17)
Bug fixes
24.2.3 (2025-03-16)
No recorded changes since last release
24.2.2 (2025-03-08)
No recorded changes since last release
24.2.1 (2025-02-28)
Bug fixes
24.2.0 (2025-02-11)
Bug fixes
Fixes for errors reported by mypy 1.11.0 by @nsoranzo in #18608
Fix transiently failing selenium tooltip issues by @jmchilton in #18847
release testing - UI tests for new workflow parameters by @jmchilton in #19182
Enhancements
Moves Libraries from Masthead to Activity Bar by @guerler in #18468
Replace History Dataset Picker in Library Folder by @itisAliRH in #18518
Workflow Invocation view improvements by @ahmedhamidawan in #18615
Guide users to collection builders by @ahmedhamidawan in #18857
Workflow license and creator edit keyboard access by @itisAliRH in #18936
Backport of Workflow Editor Activity Bar by @dannon in #19212
Various list of pairs builder usability fixes. by @jmchilton in #19248
Workflow Inputs Activity by @ElectronicBlueberry in #19252
24.1.4 (2024-12-11)
Bug fixes
Persist uploaded data between Regular and Collection upload tabs by @ahmedhamidawan in #19083
24.1.3 (2024-10-25)
No recorded changes since last release
24.1.2 (2024-09-25)
No recorded changes since last release
24.1.1 (2024-07-02)
Bug fixes
Fix (I think) a transiently failing selenium error. by @jmchilton in #18065
Enhancements
Consolidate Visualization container, avoid using default iframe by @guerler in #18016
Update Python dependencies by @galaxybot in #18063
Empower users to bring their own storage and file sources by @jmchilton in #18127
24.0.3 (2024-06-28)
No recorded changes since last release
24.0.2 (2024-05-07)
No recorded changes since last release
24.0.1 (2024-05-02)
Bug fixes
24.0.0 (2024-04-02)
Bug fixes
Update tour testing selector usage. by @jmchilton in #14005
Fix history filters taking up space in GridList by @ahmedhamidawan in #17652
Enhancements
New Workflow List and Card View by @itisAliRH in #16607
Adds delete, purge and undelete batch operations to History Grid by @guerler in #17282
Custom Multiselect by @ElectronicBlueberry in #17331
Consolidate resource grids into tab views by @guerler in #17487
23.2.1 (2024-02-21)
Enhancements
Create reusable FilterMenu with advanced options by @ahmedhamidawan in #16522
Implement datatype upload warnings by @jmchilton in #16564
Update Python dependencies by @galaxybot in #16577
Workflow Comments 💬 by @ElectronicBlueberry in #16612
Workflow Embed by @ElectronicBlueberry in #16657
Remove “Create Workflow” form and allow workflow creation in editor by @ahmedhamidawan in #16938
23.1.4 (2024-01-04)
No recorded changes since last release
23.1.3 (2023-12-01)
No recorded changes since last release
23.1.2 (2023-11-29)
No recorded changes since last release
23.1.1 (2023-10-23)
Bug fixes
Improve robustness of collection upload tests. by @jmchilton in #16093
Accessibility fixes for workflows, login, and registration. by @jmchilton in #16146
Enhancements
Upgraded to new multiselect Tags component for Workflows, DatasetList, Attributes by @hujambo-dunia in #15225
Add basic selenium test for shared histories by @davelopez in #15538
Initial end-to-end tests for separate quota sources per object store by @jmchilton in #15800
implement admin jobs filtering by @martenson in #16020
Selenium test for displaying workflows with problems in pages. by @jmchilton in #16085
Integrate accessibility testing into Selenium testing by @jmchilton in #16122
bring grids for (published) pages on par with workflows by @martenson in #16209
Small test decorator improvements. by @jmchilton in #16220
Initial e2e test for history storage. by @jmchilton in #16221
Selenium test for page history links. by @jmchilton in #16222
E2E Tests for Edit Dataset Attributes Page by @jmchilton in #16224
Selenium type fixes and annotations. by @jmchilton in #16242
e2e test for workflow license selector by @jmchilton in #16243
23.0.6 (2023-10-23)
No recorded changes since last release
23.0.5 (2023-07-29)
No recorded changes since last release
23.0.4 (2023-06-30)
No recorded changes since last release
23.0.3 (2023-06-26)
No recorded changes since last release
23.0.2 (2023-06-13)
Enhancements
23.0.1 (2023-06-08)
Enhancements
20.9.0 (2020-10-15)
First release from the 20.09 branch of Galaxy.
20.5.0 (2020-07-04)
First release from the 20.05 branch of Galaxy.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file galaxy_selenium-26.0.0.tar.gz.
File metadata
- Download URL: galaxy_selenium-26.0.0.tar.gz
- Upload date:
- Size: 84.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae16599bd5a14d8d9d950682af46d4ed909ce7864ddba146af053a1717414f67
|
|
| MD5 |
69d8c7e65722e5ce218fab1d7f137e74
|
|
| BLAKE2b-256 |
62f4e8b66f5395e7a6e131ba2f2c9f9cfaf032ef3c0ccdb27a3e7300c06a8b88
|
Provenance
The following attestation bundles were made for galaxy_selenium-26.0.0.tar.gz:
Publisher:
publish_artifacts.yaml on galaxyproject/galaxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
galaxy_selenium-26.0.0.tar.gz -
Subject digest:
ae16599bd5a14d8d9d950682af46d4ed909ce7864ddba146af053a1717414f67 - Sigstore transparency entry: 1266886357
- Sigstore integration time:
-
Permalink:
galaxyproject/galaxy@854899453b9107df24336d3b6c2cbf90ed753153 -
Branch / Tag:
refs/tags/v26.0.0 - Owner: https://github.com/galaxyproject
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_artifacts.yaml@854899453b9107df24336d3b6c2cbf90ed753153 -
Trigger Event:
release
-
Statement type:
File details
Details for the file galaxy_selenium-26.0.0-py3-none-any.whl.
File metadata
- Download URL: galaxy_selenium-26.0.0-py3-none-any.whl
- Upload date:
- Size: 78.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee7b7fbe08787c7f3bdc973498fe7f3a871d91ae93c52a8016e33d1763c8d5cb
|
|
| MD5 |
5d997bd241030122739e4029a7df61fb
|
|
| BLAKE2b-256 |
3d468eed95f528e29175a2aed70986d296f2020f8d884fb1904a70a1c527c2cb
|
Provenance
The following attestation bundles were made for galaxy_selenium-26.0.0-py3-none-any.whl:
Publisher:
publish_artifacts.yaml on galaxyproject/galaxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
galaxy_selenium-26.0.0-py3-none-any.whl -
Subject digest:
ee7b7fbe08787c7f3bdc973498fe7f3a871d91ae93c52a8016e33d1763c8d5cb - Sigstore transparency entry: 1266886675
- Sigstore integration time:
-
Permalink:
galaxyproject/galaxy@854899453b9107df24336d3b6c2cbf90ed753153 -
Branch / Tag:
refs/tags/v26.0.0 - Owner: https://github.com/galaxyproject
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_artifacts.yaml@854899453b9107df24336d3b6c2cbf90ed753153 -
Trigger Event:
release
-
Statement type: