-
+
-
+
@@ -112,13 +121,17 @@ async function sendFeedback(value: "up" | "down") {
-
diff --git a/client/src/utils/navigation/navigation.yml b/client/src/utils/navigation/navigation.yml
index 2db7e8dcc48..58416ea8d1f 100644
--- a/client/src/utils/navigation/navigation.yml
+++ b/client/src/utils/navigation/navigation.yml
@@ -1475,6 +1475,35 @@ chatgxy:
feedback_ack: '.entry-response .feedback-ack'
meta_tag: '.entry-response .meta-tag'
+galaxy_wizard:
+ selectors:
+ _:
+ selector: 'galaxy wizard'
+ type: data-description
+ analyze_button:
+ selector: 'galaxy wizard analyze button'
+ type: data-description
+ loading:
+ selector: 'galaxy wizard loading'
+ type: data-description
+ response:
+ selector: 'galaxy wizard response'
+ type: data-description
+ feedback_section:
+ selector: 'galaxy wizard feedback'
+ type: data-description
+ feedback_up:
+ selector: 'galaxy wizard feedback up'
+ type: data-description
+ feedback_down:
+ selector: 'galaxy wizard feedback down'
+ type: data-description
+ feedback_ack:
+ selector: 'galaxy wizard feedback ack'
+ type: data-description
+ wizard_card:
+ selector: 'galaxy wizard card'
+ type: data-description
zip_import_wizard:
selectors:
diff --git a/lib/galaxy/selenium/navigates_galaxy.py b/lib/galaxy/selenium/navigates_galaxy.py
index cc538777f51..a82f830f406 100644
--- a/lib/galaxy/selenium/navigates_galaxy.py
+++ b/lib/galaxy/selenium/navigates_galaxy.py
@@ -1634,6 +1634,21 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
assert len(chatgxy.query_cell.all()) == 0
assert len(chatgxy.response_content.all()) == 0
+ def navigate_to_dataset_error(self, hid):
+ """Display a dataset and click the error tab."""
+ self.display_dataset(hid)
+ error_tab = self.wait_for_selector_clickable(
+ ".nav-item[title='View error information for this dataset'] > a.nav-link"
+ )
+ error_tab.click()
+
+ def galaxy_wizard_analyze(self):
+ """Click the wizard analyze button and wait for the response."""
+ wizard = self.components.galaxy_wizard
+ wizard.analyze_button.wait_for_and_click()
+ # Button disappears once queryResponse is set (v-if="!queryResponse")
+ wizard.analyze_button.wait_for_absent_or_hidden()
+
def navigate_to_pages(self):
self.home()
self.components.pages.activity.wait_for_and_click()
diff --git a/lib/galaxy_test/selenium/test_galaxy_wizard.py b/lib/galaxy_test/selenium/test_galaxy_wizard.py
new file mode 100644
index 00000000000..94dfb623348
--- /dev/null
+++ b/lib/galaxy_test/selenium/test_galaxy_wizard.py
@@ -0,0 +1,69 @@
+"""E2E tests for the GalaxyWizard inline error analysis widget.
+
+Uses the static agent backend for deterministic assertions — no LLM calls.
+Skipped when agents are not configured (skip_without_agents decorator).
+"""
+
+from galaxy_test.base.populators import skip_without_agents
+from .framework import (
+ managed_history,
+ retry_assertion_during_transitions,
+ selenium_test,
+ SeleniumTestCase,
+)
+
+
+class TestGalaxyWizard(SeleniumTestCase):
+ ensure_registered = True
+
+ def create_failed_dataset(self):
+ """Run detect_errors tool with stderr output to produce a failed dataset."""
+ history_id = self.current_history_id()
+ inputs = {
+ "stdoutmsg": "",
+ "stderrmsg": "error: tool configuration failure detected",
+ "exit_code": "6",
+ }
+ response = self.dataset_populator.run_tool("detect_errors", inputs, history_id)
+ self.dataset_populator.wait_for_history(history_id, assert_ok=False)
+ failed_hid = response["outputs"][0]["hid"]
+ return history_id, failed_hid
+
+ @skip_without_agents
+ @selenium_test
+ @managed_history
+ def test_wizard_error_analysis_flow(self):
+ """Create failed dataset, analyze error, verify response and feedback."""
+ # Setup: create a failed dataset via API
+ history_id, failed_hid = self.create_failed_dataset()
+ self.history_panel_wait_for_hid_state(failed_hid, "error")
+ self.screenshot("galaxy_wizard_error_dataset_in_history")
+
+ # Navigate to error view
+ self.navigate_to_dataset_error(failed_hid)
+ wizard = self.components.galaxy_wizard
+
+ # Wizard section visible (agents configured)
+ wizard.analyze_button.wait_for_visible()
+ self.screenshot("galaxy_wizard_before_analyze")
+
+ # Click analyze, wait for response
+ self.galaxy_wizard_analyze()
+ self.screenshot("galaxy_wizard_response_received")
+
+ # Verify response content from static backend
+ @retry_assertion_during_transitions
+ def assert_response():
+ assert "tool configuration issue" in wizard.response.wait_for_text()
+
+ assert_response()
+
+ # Feedback
+ wizard.feedback_up.wait_for_and_click()
+
+ @retry_assertion_during_transitions
+ def assert_feedback():
+ assert "Thank you" in wizard.feedback_ack.wait_for_text()
+
+ assert_feedback()
+ self.screenshot("galaxy_wizard_feedback_submitted")
diff --git a/test/functional/tools/detect_errors.xml b/test/functional/tools/detect_errors.xml
index 69cee555fee..9396becae4f 100644
--- a/test/functional/tools/detect_errors.xml
+++ b/test/functional/tools/detect_errors.xml
@@ -15,7 +15,7 @@
echo '$stdoutmsg' &&
#end if
#if str($stderrmsg) != ""
- >2& echo '$stderrmsg' &&
+ >&2 echo '$stderrmsg' &&
#end if
sh -c 'exit $exit_code'
]]>
@@ -37,10 +37,10 @@ sh -c 'exit $exit_code'
-
+
diff --git a/test/unit/tool_util/test_parsing.py b/test/unit/tool_util/test_parsing.py
index 07f847de8ed..90f073b78d1 100644
--- a/test/unit/tool_util/test_parsing.py
+++ b/test/unit/tool_util/test_parsing.py
@@ -948,8 +948,8 @@ class TestExpectations(FunctionalTestToolTestCase):
tests = tests_dict["tests"]
assert len(tests) == 10
test_0 = tests[0]
- assert len(test_0["stderr"]) == 1
- assert len(test_0["stdout"]) == 2
+ assert len(test_0["stderr"]) == 2
+ assert len(test_0["stdout"]) == 1
class TestExpectationsCommandVersion(FunctionalTestToolTestCase):