diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py
index d1f50b945c28..1fae939dd5d1 100644
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -3670,6 +3670,17 @@ def element_is_valid(element: model.DatasetCollectionElement):
return False
+class FilterNullTool(FilterDatasetsTool):
+ tool_type = "filter_null"
+ require_dataset_ok = True
+
+ @staticmethod
+ def element_is_valid(element: model.DatasetCollectionElement):
+ element_object = element.element_object
+ assert isinstance(element_object, model.DatasetInstance)
+ return element_object.extension == "expression.json" and element_object.blurb == "skipped"
+
+
class FlattenTool(DatabaseOperationTool):
tool_type = "flatten_collection"
require_terminal_states = False
diff --git a/lib/galaxy_test/api/test_workflow_build_module.py b/lib/galaxy_test/api/test_workflow_build_module.py
new file mode 100644
index 000000000000..546f6192e397
--- /dev/null
+++ b/lib/galaxy_test/api/test_workflow_build_module.py
@@ -0,0 +1,19 @@
+from galaxy_test.base.populators import (
+ skip_without_tool,
+ WorkflowPopulator,
+)
+from ._framework import ApiTestCase
+
+
+class TestBuildWorkflowModule(ApiTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.workflow_populator = WorkflowPopulator(self.galaxy_interactor)
+
+ @skip_without_tool("select_from_url")
+ def test_build_module_filter_dynamic_select(self):
+ # Verify that filtering on parameters that depend on parameter and validators works
+ # fine in workflow building mode.
+ module = self.workflow_populator.build_module(step_type="tool", content_id="select_from_url")
+ assert not module["errors"], module["errors"]
diff --git a/lib/galaxy_test/base/populators.py b/lib/galaxy_test/base/populators.py
index 014880ebd1e6..bd5feaa01592 100644
--- a/lib/galaxy_test/base/populators.py
+++ b/lib/galaxy_test/base/populators.py
@@ -2298,6 +2298,12 @@ def import_tool(self, tool) -> Dict[str, Any]:
assert upload_response.status_code == 200, upload_response
return upload_response.json()
+ def build_module(self, step_type: str, content_id: Optional[str] = None, inputs: Optional[Dict[str, Any]] = None):
+ payload = {"inputs": inputs or {}, "type": step_type, "content_id": content_id}
+ response = self._post("workflows/build_module", data=payload, json=True)
+ assert response.status_code == 200, response
+ return response.json()
+
def _import_tool_response(self, tool) -> Response:
using_requirement("admin")
tool_str = json.dumps(tool, indent=4)
diff --git a/test/functional/tools/select_from_url.xml b/test/functional/tools/select_from_url.xml
index 60a712e74631..488055677e85 100644
--- a/test/functional/tools/select_from_url.xml
+++ b/test/functional/tools/select_from_url.xml
@@ -10,6 +10,13 @@ echo '$url_param_value_header_and_body' > '$param_value_header_and_body'
+
+
+
+
+
+
+