Skip to content

Commit 9f5e9cc

Browse files
committed
Preserve falsy workflow parameter values on workflow rerun
Re-running a workflow invocation through the simple run form silently discarded `false`, `0`, and `""` values for `parameter_input` steps and fell back to the workflow's default. The rerun-state hydration in WorkflowRunFormSimple.vue used truthiness checks (`if (requestState[k])` and `if (value)`) where it should have checked for key presence and `!== undefined`. As a result a boolean parameter set to `false` on the original run came back as the default `true` on rerun, with no "Changed Input" badge to flag the discrepancy. Switch the lookup to `key in requestState` and the assignment guard to `value !== undefined` so falsy-but-defined values are preserved. Add a selenium regression test that runs gx_boolean with the parameter toggled to false, reruns, and asserts both the form state (preserved false, no changed-input badge; toggling to true raises the badge) and the new invocation's Inputs tab.
1 parent feccf57 commit 9f5e9cc

3 files changed

Lines changed: 93 additions & 7 deletions

File tree

client/src/components/Workflow/Run/WorkflowRunFormSimple.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,18 @@ const formInputs = computed(() => {
161161
if (props.requestState) {
162162
if (props.isRerun) {
163163
const requestStateKeys = Object.keys(props.requestState);
164+
const stateKey = String(rerunStateIndex);
164165
165166
let value;
166-
if (props.requestState[rerunStateIndex]) {
167+
if (stateKey in props.requestState) {
167168
// request state has the step_label as key
168-
value = props.requestState[rerunStateIndex];
169-
} else if (requestStateKeys[i] !== undefined && requestStateKeys[i] === "") {
169+
value = props.requestState[stateKey];
170+
} else if (requestStateKeys[i] === "") {
170171
// request state has "" as key on the `i` position
171172
value = Object.values(props.requestState)[i];
172173
}
173174
174-
if (value) {
175+
if (value !== undefined) {
175176
if (stepType === "data_input" || stepType === "data_collection_input") {
176177
// Note: This is different from workflow landings because `WorkflowInvocationRequestModel`
177178
// does not provide an object with `values` property.
@@ -182,9 +183,8 @@ const formInputs = computed(() => {
182183
stepAsInput.value = value;
183184
}
184185
}
185-
} else if (props.requestState[stepLabel]) {
186-
const value = props.requestState[stepLabel];
187-
stepAsInput.value = value;
186+
} else if (String(stepLabel) in props.requestState) {
187+
stepAsInput.value = props.requestState[String(stepLabel)];
188188
}
189189
}
190190

client/src/utils/navigation/navigation.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ tool_form:
648648
parameter_div: 'div.ui-form-element[id="form-element-${parameter}"]'
649649
parameter_error: 'div.ui-form-element[id="form-element-${parameter}"] .ui-form-error-text'
650650
parameter_checkbox: 'div.ui-form-element[id="form-element-${parameter}"] .ui-switch'
651+
parameter_checkbox_input: 'div.ui-form-element[id="form-element-${parameter}"] input[type="checkbox"]'
651652
parameter_select: 'div.ui-form-element[id="form-element-${parameter}"] .multiselect'
652653
parameter_input: 'div.ui-form-element[id="form-element-${parameter}"] .ui-input'
653654
parameter_textarea: 'div.ui-form-element[id="form-element-${parameter}"] textarea'

lib/galaxy_test/selenium/test_workflow_rerun.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from selenium.webdriver.common.by import By
2+
13
from galaxy_test.base.workflow_fixtures import WORKFLOW_SIMPLE_CAT_TWICE
24
from .framework import (
35
managed_history,
@@ -9,6 +11,19 @@
911
UsesHistoryItemAssertions,
1012
)
1113

14+
WORKFLOW_BOOLEAN_PARAMETER_DEFAULT_TRUE = """
15+
class: GalaxyWorkflow
16+
inputs:
17+
bool_param:
18+
type: boolean
19+
default: true
20+
steps:
21+
echo_bool:
22+
tool_id: gx_boolean
23+
in:
24+
parameter: bool_param
25+
"""
26+
1227

1328
class TestWorkflowRun(SeleniumTestCase, UsesHistoryItemAssertions, RunsWorkflows):
1429
ensure_registered = True
@@ -65,6 +80,76 @@ def test_workflow_rerun(self):
6580
form_element.changed_value_badge.wait_for_visible()
6681
self.screenshot("workflow_rerun_changed_input")
6782

83+
@selenium_test
84+
@managed_history
85+
def test_workflow_rerun_preserves_false_boolean_parameter(self):
86+
"""Regression test for boolean workflow parameters reverting to default on rerun.
87+
88+
Setting a boolean ``parameter_input`` to ``false`` (overriding a
89+
``default: true``), running the workflow, and re-running the invocation
90+
previously caused the form to silently fall back to the default value
91+
because of a falsy-value check in WorkflowRunFormSimple.vue. The form
92+
should instead show the value the user actually used.
93+
"""
94+
invocations = self.components.invocations
95+
96+
self.workflow_run_open_workflow(WORKFLOW_BOOLEAN_PARAMETER_DEFAULT_TRUE)
97+
98+
# Override the boolean default of true to false before submitting.
99+
# The boolean is the workflow's only input, hence step_index 0.
100+
self._toggle_workflow_run_boolean(parameter="0", target=False)
101+
self.screenshot("workflow_run_boolean_false_before_submit")
102+
103+
self.workflow_run_submit()
104+
self.sleep_for(self.wait_types.UX_TRANSITION)
105+
self.workflow_run_wait_for_ok(hid=1)
106+
107+
# Submitting lands us on the new invocation page; the rerun button is
108+
# right there on the invocation state details. We're still in the
109+
# invocation's history, so no "switch history" confirmation appears.
110+
invocations.state_details.wait_for_visible()
111+
invocations.workflow_rerun_button.wait_for_and_click()
112+
self.sleep_for(self.wait_types.UX_TRANSITION)
113+
114+
# The boolean should be preserved as false on the rerun form rather than
115+
# silently reset to the workflow's default of true.
116+
checkbox = self.components.tool_form.parameter_checkbox_input(parameter="0").wait_for_present()
117+
assert (
118+
not checkbox.is_selected()
119+
), "Boolean parameter input was reset to its default 'true' instead of preserving the previous run's 'false' value"
120+
121+
# Without changes, the boolean should not be flagged as a changed input.
122+
form_element = self.components.workflow_run.form_element._(index=0)
123+
form_element.changed_value_badge.assert_absent()
124+
self.screenshot("workflow_rerun_boolean_preserved_false")
125+
126+
# Toggling the value back to true should flag it as changed.
127+
self._toggle_workflow_run_boolean(parameter="0", target=True)
128+
form_element.changed_value_badge.wait_for_visible()
129+
self.screenshot("workflow_rerun_boolean_changed_input")
130+
131+
# Submit the rerun and verify the new invocation actually recorded the
132+
# value shown in the form (true) on its Inputs tab.
133+
self.workflow_run_submit()
134+
self.sleep_for(self.wait_types.UX_TRANSITION)
135+
self.workflow_run_wait_for_ok(hid=2)
136+
invocations.state_details.wait_for_visible()
137+
invocations.invocation_tab(label="Inputs").wait_for_and_click()
138+
self._assert_input_table_has_parameter("bool_param", "true")
139+
self.screenshot("workflow_rerun_boolean_inputs_tab")
140+
141+
@retry_assertion_during_transitions
142+
def _assert_input_table_has_parameter(self, label: str, value: str):
143+
table = self.driver.find_element(By.CSS_SELECTOR, '[data-description="input table"]')
144+
text = table.text
145+
assert label in text, f"Expected input label '{label}' in inputs table, got: {text!r}"
146+
assert value in text, f"Expected input value '{value}' in inputs table, got: {text!r}"
147+
148+
def _toggle_workflow_run_boolean(self, parameter: str, target: bool):
149+
checkbox = self.components.tool_form.parameter_checkbox_input(parameter=parameter).wait_for_present()
150+
if checkbox.is_selected() != target:
151+
self.execute_script("arguments[0].click();", checkbox)
152+
68153
@retry_assertion_during_transitions
69154
def _assert_history_name_is(self, expected_name=None):
70155
name = self.history_panel_name()

0 commit comments

Comments
 (0)