Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ const props = defineProps<{
</script>

<template>
<span class="d-flex align-items-center">
<span
class="d-flex align-items-center"
data-description="invocation step state counter"
:data-state="state"
:data-count="jobCount">
<FontAwesomeIcon
v-if="iconClasses[props.state]"
:icon="iconClasses[props.state]?.icon"
Expand Down
1 change: 1 addition & 0 deletions client/src/utils/navigation/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,7 @@ invocations:
selector: '//span[contains(@class, "content-title name")][text()="${element_identifier}"]'
step_output_collection_element_datatype: '[data-step="${order_index}"] .invocation-step-output-collection-details .not-loading .datatype .value'
step_job_details: '[data-step="${order_index}"] .invocation-step-job-details'
step_job_details_state_counter: '[data-description="invocation step state counter"][data-state="${state}"]'
step_job_information: '[data-step="${order_index}"] .invocation-step-job-details .info_data_table'
step_job_information_tool_id: '[data-step="${order_index}"] .invocation-step-job-details .info_data_table #galaxy-tool-id'
export_tab: '.invocation-export-tab'
Expand Down
34 changes: 4 additions & 30 deletions lib/galaxy_test/api/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
NESTED_WORKFLOW_WITH_CONDITIONAL_SUBWORKFLOW_AND_DISCONNECTED_MAP_OVER_SOURCE,
WORKFLOW_FLAT_CROSS_PRODUCT,
WORKFLOW_INPUTS_AS_OUTPUTS,
WORKFLOW_KEEP_SUCCESSFUL_DATASETS,
WORKFLOW_KEEP_SUCCESSFUL_DATASETS_TEST_DATA,
WORKFLOW_LIST_PAIRED_INPUT_TO_TYPE_SOURCE,
WORKFLOW_NESTED_REPLACEMENT_PARAMETER,
WORKFLOW_NESTED_RUNTIME_PARAMETER,
Expand Down Expand Up @@ -3790,36 +3792,8 @@ def filter_jobs_by_tool(tool_id):
def test_keep_success_mapping_error(self):
with self.dataset_populator.test_history() as history_id:
summary = self._run_workflow(
"""
class: GalaxyWorkflow
inputs:
input_c: collection

steps:
mixed_collection:
tool_id: exit_code_from_file
in:
input: input_c

filtered_collection:
tool_id: "__KEEP_SUCCESS_DATASETS__"
in:
input: mixed_collection/out_file1

cat:
tool_id: cat1
in:
input1: filtered_collection/output
""",
test_data="""
input_c:
collection_type: list
elements:
- identifier: i1
content: "0"
- identifier: i2
content: "1"
""",
WORKFLOW_KEEP_SUCCESSFUL_DATASETS,
test_data=WORKFLOW_KEEP_SUCCESSFUL_DATASETS_TEST_DATA,
history_id=history_id,
wait=True,
assert_ok=False,
Expand Down
32 changes: 32 additions & 0 deletions lib/galaxy_test/base/workflow_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1280,3 +1280,35 @@
"uuid": "03a95ebe-af1e-4628-ac2f-e7553babfb2f",
"version": 3
}"""

WORKFLOW_KEEP_SUCCESSFUL_DATASETS = """
class: GalaxyWorkflow
inputs:
input_c: collection

steps:
mixed_collection:
tool_id: exit_code_from_file
in:
input: input_c

filtered_collection:
tool_id: "__KEEP_SUCCESS_DATASETS__"
in:
input: mixed_collection/out_file1

cat:
tool_id: cat
in:
input1: filtered_collection/output
"""

WORKFLOW_KEEP_SUCCESSFUL_DATASETS_TEST_DATA = """
input_c:
collection_type: list
elements:
- identifier: i1
content: "0"
- identifier: i2
content: "1"
"""
109 changes: 86 additions & 23 deletions lib/galaxy_test/selenium/test_workflow_invocation_details.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from galaxy_test.base.workflow_fixtures import WORKFLOW_WITH_OUTPUT_COLLECTION
from galaxy_test.base.workflow_fixtures import (
WORKFLOW_KEEP_SUCCESSFUL_DATASETS,
WORKFLOW_KEEP_SUCCESSFUL_DATASETS_TEST_DATA,
WORKFLOW_WITH_OUTPUT_COLLECTION,
)
from .framework import (
managed_history,
retry_assertion_during_transitions,
selenium_test,
SeleniumTestCase,
Expand All @@ -17,29 +22,9 @@ def test_job_details(self):
WORKFLOW_WITH_OUTPUT_COLLECTION, history_id=history_id, assert_ok=True, wait=True
)

# open invocations panel
self.home()
gx_selenium_context.components.invocations.activity.wait_for_and_click()

invocations = gx_selenium_context.components.invocations
invocations.invocations_panel_list.wait_for_visible()

@retry_assertion_during_transitions
def assert_has_row():
invocations.invocations_panel_list_items.wait_for_visible()
invocation_rows = invocations.invocations_panel_list_items.all()
assert len(invocation_rows) > 0
return invocation_rows[0]

assert_has_row()

invocations.state_details.assert_absent()
details = invocations.invocations_panel_list_items.all()[0]
details.click()
invocations.state_details.wait_for_visible()
self.invocation_open_latest()

# close invocations panel
gx_selenium_context.components.invocations.activity.wait_for_and_click()
invocations = self.components.invocations

@retry_assertion_during_transitions
def assert_progress_steps_note_contains(text):
Expand Down Expand Up @@ -77,3 +62,81 @@ def assert_progress_steps_note_contains(text):
invocations.step_output_collection_element_identifier(element_identifier="forward").wait_for_and_click()
datatype = invocations.step_output_collection_element_datatype(order_index="1").wait_for_text()
assert datatype == "txt"

@selenium_test
@managed_history # failed job messes with some history wait code we probably shouldn't be using
def test_invocation_step_jobs_with_failed_jobs(self):
"""Test invocation step jobs view with mixed successful and failed jobs.

This test verifies:
- Job state counters (ok and error) display correctly for steps with mixed job states
- Filtering by failed jobs works correctly
- Debug tab shows only failed steps
- Failed steps can be expanded in debug view
"""
history_id = self.current_history_id()
self.workflow_populator.run_workflow(
WORKFLOW_KEEP_SUCCESSFUL_DATASETS,
test_data=WORKFLOW_KEEP_SUCCESSFUL_DATASETS_TEST_DATA,
history_id=history_id,
assert_ok=False,
)

# Open the first invocation
self.invocation_open_latest()

# Navigate to Steps tab
invocations = self.components.invocations
invocations.invocation_tab(label="Steps").wait_for_and_click()

# Click on a step with multiple mixed failed and successful jobs
invocations.step_details(order_index="1").wait_for_and_click()
invocations.step_job_details(order_index="1").wait_for_visible()

# Verify job state counters
okay_counter = invocations.step_job_details_state_counter(state="ok").wait_for_visible()
failed_counter = invocations.step_job_details_state_counter(state="error").wait_for_visible()
assert okay_counter.get_attribute("data-count") == "1"
assert failed_counter.get_attribute("data-count") == "1"
self.screenshot("invocation_steps_view_with_failed_jobs")

# Filter by failed jobs
invocations.step_job_details_state_counter(state="error").wait_for_and_click()
self.screenshot("invocation_steps_view_with_failed_jobs_failed_jobs_list")

# Navigate to Debug tab
invocations.invocation_tab(label="Debug").wait_for_and_click()

# Verify the failed step appears here and the successful step doesn't
self.screenshot("invocation_steps_view_with_failed_jobs_debug_landing")
invocations.step_title(order_index=1).wait_for_and_click()
invocations.step_title(order_index=2).assert_absent()
self.screenshot("invocation_steps_view_with_failed_jobs_debug_job_expanded")

def invocation_open_latest(self):
# TODO: migrate retry_assertion_during_transitions to navigates_galaxy.py so this
# can be moved there.

# open invocations panel
self.home()
self.components.invocations.activity.wait_for_and_click()

invocations = self.components.invocations
invocations.invocations_panel_list.wait_for_visible()

@retry_assertion_during_transitions
def assert_has_row():
invocations.invocations_panel_list_items.wait_for_visible()
invocation_rows = invocations.invocations_panel_list_items.all()
assert len(invocation_rows) > 0
return invocation_rows[0]

assert_has_row()

invocations.state_details.assert_absent()
details = invocations.invocations_panel_list_items.all()[0]
details.click()
invocations.state_details.wait_for_visible()

# close invocations panel
self.components.invocations.activity.wait_for_and_click()
Loading