Files
galaxy/lib/galaxy_test/selenium/test_custom_tools.py
T
2026-01-20 10:25:45 +00:00

132 lines
4.7 KiB
Python

"""Selenium tests for custom tool creation and management."""
import platform
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from .framework import (
selenium_only,
selenium_test,
SeleniumTestCase,
)
class TestCustomTools(SeleniumTestCase):
ensure_registered = True
def assert_baseline_accessibility(self):
"""Skip accessibility checks for custom tools tests due to Monaco editor issues."""
pass
@selenium_only("Not yet migrated to support Playwright backend")
@selenium_test
def test_create_custom_tool(self):
"""Test creating a new custom tool through the UI."""
with self.dataset_populator.user_tool_execute_permissions():
tool_uuid = self.create_new_custom_tool()
assert tool_uuid, "Tool UUID should be returned after saving."
self.components.custom_tools.tool_link(tool_uuid=tool_uuid).wait_for_clickable()
@selenium_only("Not yet migrated to support Playwright backend")
@selenium_test
def test_run_custom_tool(self):
test_path = self.get_filename("1.fasta")
self.perform_upload(test_path, on_current_page=True)
self.history_panel_wait_for_hid_ok(1)
with self.dataset_populator.user_tool_execute_permissions():
tool_uuid = self.create_new_custom_tool()
assert tool_uuid, "Tool UUID should be returned after saving."
self.components.custom_tools.tool_link(tool_uuid=tool_uuid).wait_for_and_click()
self.sleep_for(self.wait_types.UX_RENDER)
self.components.tool_form.execute.wait_for_and_click()
self.history_panel_wait_for_hid_ok(2)
self.hda_click_primary_action_button(2, "rerun")
self.components.tool_form.execute.wait_for_and_click()
self.history_panel_wait_for_hid_ok(3)
def create_new_custom_tool(self) -> str:
self.home()
self.open_tool_editor()
self.paste_tool()
return self.save_tool()
def open_tool_editor(self):
# Navigate via Custom Tools activity panel
self.components.custom_tools.activity.wait_for_and_click()
# Use the component selector for the create button
self.components.custom_tools.create_button.wait_for_and_click()
# Wait for the Tool Editor heading to appear
self.wait_for_selector_visible("h1")
self.wait_for_selector_visible(".monaco-editor")
def save_tool(self) -> str:
self.components.custom_tools.save_button.wait_for_and_click()
# Wait for save operation to complete
self.sleep_for(self.wait_types.UX_TRANSITION)
# Verify save was successful
current_url = self.driver.current_url
return current_url.split("/tools/editor/")[1]
def paste_tool(self):
# Define a simple custom tool YAML
tool_yaml_one = """class: GalaxyUserTool
id: test_cat_tool
name: Test Cat Tool
version: "0.1"
description: Concatenate test files
container: busybox
shell_command: |
cat $(inputs.datasets.map((input) => input.path).join(' ')) > output.txt
"""
tool_yaml_two = """
inputs:
- name: datasets
multiple: true
type: data
"""
tool_yaml_three = """
outputs:
- name: output1
type: data
format_source: datasets
from_work_dir: output.txt
"""
# Try finding Monaco editor and replace skeleton content
self.sleep_for(self.wait_types.UX_RENDER) # Allow editor to initialize
# Use the stable .monaco-editor container, not .view-line which gets re-rendered
editor_container = self.wait_for_selector_visible(".monaco-editor")
# Focus the editor by clicking on the stable container
editor_container.click()
self.sleep_for(self.wait_types.UX_RENDER) # Allow editor to focus
is_mac = platform.system() == "Darwin"
modifier_key = Keys.COMMAND if is_mac else Keys.CONTROL
action_chains = ActionChains(self.driver)
# Select all content
action_chains.key_down(modifier_key)
action_chains.send_keys("a")
action_chains.key_up(modifier_key)
action_chains.perform()
# Delete selected content
action_chains = ActionChains(self.driver)
action_chains.send_keys(Keys.DELETE)
action_chains.perform()
# Now insert the new content
# yaml is split in funky was to accomodate guided yaml text input in monaco
action_chains = ActionChains(self.driver)
action_chains.send_keys(tool_yaml_one)
action_chains.send_keys(Keys.BACKSPACE)
action_chains.send_keys(tool_yaml_two)
action_chains.send_keys(Keys.BACKSPACE)
action_chains.send_keys(tool_yaml_three)
action_chains.perform()