Warning
This document is for an old release of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.
Source code for galaxy_test.selenium.test_tool_form
import json
from typing import (
Any,
Dict,
List,
)
import pytest
from selenium.webdriver.common.by import By
from galaxy.model.unittest_utils.store_fixtures import one_hda_model_store_dict
from galaxy.selenium.navigates_galaxy import retry_call_during_transitions
from galaxy.util.unittest_utils import skip_if_github_down
from galaxy_test.base import rules_test_data
from galaxy_test.base.populators import (
flakey,
stage_rules_example,
)
from .framework import (
managed_history,
retry_assertion_during_transitions,
selenium_test,
SeleniumTestCase,
UsesHistoryItemAssertions,
)
[docs]class TestToolForm(SeleniumTestCase, UsesHistoryItemAssertions):
[docs] @selenium_test
def test_run_tool_verify_contents_by_peek(self):
self._run_environment_test_tool()
self.history_panel_wait_for_hid_ok(1)
self.history_panel_click_item_title(hid=1)
self.assert_item_peek_includes(1, "42")
[docs] @selenium_test
def test_run_tool_verify_dataset_details(self):
self._run_environment_test_tool()
self.history_panel_wait_for_hid_ok(1)
self._check_dataset_details_for_inttest_value(1)
[docs] @selenium_test
def test_verify_dataset_details_tables(self):
self._run_environment_test_tool()
self.history_panel_wait_for_hid_ok(1)
hda = self.latest_history_item()
self._check_dataset_details_for_inttest_value(1)
dataset_details_key_value_pairs = self._table_to_key_value_elements("table#dataset-details")
number_found = name_found = format_found = False
for key, value in dataset_details_key_value_pairs:
if "Number" in key.text:
assert str(hda["hid"]) in value.text
number_found = True
if "Name" in key.text:
assert hda["name"] in value.text
name_found = True
if "Format" in key.text:
assert hda["extension"] in value.text
format_found = True
assert number_found
assert name_found
assert format_found
job_outputs = self._table_to_key_value_elements("table#job-outputs")
assert job_outputs[0][0].text == "environment_variables"
generic_item = job_outputs[0][1]
assert "1: environment_variables" in generic_item.text
generic_item.click()
self.sleep_for(self.wait_types.UX_RENDER)
assert generic_item.find_element(By.CSS_SELECTOR, "pre").text == "42\nmoo\nNOTTHREE"
generic_item.find_element(By.CSS_SELECTOR, "[title='Run Job Again']").click()
self.components.tool_form.execute.wait_for_visible()
[docs] @selenium_test
def test_drilldown_tool(self):
self._open_drilldown_test_tool()
# click first option in first drilldown component
self.wait_for_and_click(self.components.tool_form.drilldown_expand)
self.wait_for_and_click(self.components.tool_form.drilldown_option)
# click select all in second drilldown component
self.wait_for_and_click(self.components.tool_form.drilldown_select_all(parameter="dd_recurse"))
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(1)
# click hid 1 in history panel
self.history_panel_click_item_title(hid=1)
# assert that the dataset peek is d = a dd_recurse = a,b,c
self.assert_item_peek_includes(1, "dd a")
self.assert_item_peek_includes(1, "dd_recurse aa,aba,abb,ba,bba,bbb")
def _open_drilldown_test_tool(self):
self.home()
self.tool_open("drill_down")
def _table_to_key_value_elements(self, table_selector):
tool_parameters_table = self.wait_for_selector_visible(table_selector)
tbody_element = tool_parameters_table.find_element(By.CSS_SELECTOR, "tbody")
trs = tbody_element.find_elements(By.CSS_SELECTOR, "tr")
assert trs
key_value_pairs = []
for tr in trs:
tds = tr.find_elements(By.CSS_SELECTOR, "td")
assert tds
key_value_pairs.append((tds[0], tds[1]))
return key_value_pairs
[docs] @selenium_test
def test_repeat_reordering(self):
self.home()
self.tool_open("text_repeat")
def assert_input_order(inputs: List[str]):
for index, input in enumerate(inputs):
parameter_input = self.components.tool_form.parameter_input(parameter=f"the_repeat_{index}|texttest")
parameter_value = parameter_input.wait_for_value()
assert parameter_value == input
self.components.tool_form.repeat_insert.wait_for_and_click()
self.tool_set_value("the_repeat_0|texttest", "Text A")
self.components.tool_form.repeat_insert.wait_for_and_click()
self.tool_set_value("the_repeat_1|texttest", "Text B")
self.components.tool_form.repeat_insert.wait_for_and_click()
self.tool_set_value("the_repeat_2|texttest", "Text C")
assert_input_order(["Text A", "Text B", "Text C"])
self.components.tool_form.repeat_move_up(parameter="the_repeat_1").wait_for_and_click()
assert_input_order(["Text B", "Text A", "Text C"])
self.components.tool_form.repeat_move_up(parameter="the_repeat_2").wait_for_and_click()
assert_input_order(["Text B", "Text C", "Text A"])
self.components.tool_form.repeat_move_up(parameter="the_repeat_1").wait_for_and_click()
assert_input_order(["Text C", "Text B", "Text A"])
self.components.tool_form.repeat_move_up(parameter="the_repeat_0").wait_for_and_click()
assert_input_order(["Text C", "Text B", "Text A"])
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(1)
details = list(map(lambda d: d.text, self._get_dataset_tool_parameters(1)))
assert details == ["texttest", "Text C", "texttest", "Text B", "texttest", "Text A"]
[docs] @selenium_test
def test_rerun(self):
self._run_environment_test_tool()
self.history_panel_wait_for_hid_ok(1)
self.hda_click_primary_action_button(1, "rerun")
def check_recorded_val():
inttest_div_element = self.tool_parameter_div("inttest")
inttest_input_element = inttest_div_element.find_element(By.CSS_SELECTOR, "input")
recorded_val = inttest_input_element.get_attribute("value")
# Assert form re-rendered with correct value in textbox.
assert recorded_val == "42", recorded_val
# These form entries seem to be replaced/updated occasionally
# causing stale elements.
retry_call_during_transitions(check_recorded_val)
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(2)
self._check_dataset_details_for_inttest_value(2)
[docs] @selenium_test
def test_rerun_deleted_dataset(self):
# upload a first dataset that should not become selected on re-run
test_path = self.get_filename("1.tabular")
self.perform_upload(test_path)
self.history_panel_wait_for_hid_ok(1)
self.tool_open("column_param")
self.select_set_value("#col", "3")
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(2)
# delete source dataset and click re-run on resulting dataset
item = self.history_panel_item_component(hid=1)
item.delete_button.wait_for_and_click()
item = self.history_panel_item_component(hid=2)
item.title.wait_for_and_click()
item.rerun_button.wait_for_and_click()
# validate initial warnings
error_input1 = self.components.tool_form.parameter_error(parameter="input1").wait_for_visible()
error_col = self.components.tool_form.parameter_error(parameter="col").wait_for_visible()
assert (
error_input1.text
== "parameter 'input1': the previously selected dataset has been deleted. Using default: ''."
)
assert error_col.text == "parameter 'col': an invalid option ('3') was selected (valid options: 1)"
# validate errors when inputs are missing
self.components.tool_form.parameter_data_input_collection(parameter="input1").wait_for_and_click()
self.sleep_for(self.wait_types.UX_TRANSITION)
error_input1 = self.components.tool_form.parameter_error(parameter="input1").wait_for_visible()
error_col = self.components.tool_form.parameter_error(parameter="col").wait_for_visible()
error_col_names = self.components.tool_form.parameter_error(parameter="col_names").wait_for_visible()
assert error_input1.text == "Please provide a value for this option."
assert error_col.text == "parameter 'col': requires a value, but no legal values defined"
assert error_col_names.text == "parameter 'col_names': requires a value, but no legal values defined"
# validate warnings when inputs are restored
self.components.tool_form.parameter_data_input_single(parameter="input1").wait_for_and_click()
self.sleep_for(self.wait_types.UX_TRANSITION)
error_input1 = self.components.tool_form.parameter_error(parameter="input1").wait_for_visible()
error_col = self.components.tool_form.parameter_error(parameter="col").wait_for_visible()
assert (
error_input1.text
== "parameter 'input1': the previously selected dataset has been deleted. Using default: ''."
)
assert error_col.text == "parameter 'col': an invalid option ('3') was selected (valid options: 1)"
[docs] @selenium_test
def test_rerun_dataset_collection_element(self):
# upload a first dataset that should not become selected on re-run
test_path = self.get_filename("1.fasta")
self.perform_upload(test_path)
self.history_panel_wait_for_hid_ok(1)
history_id = self.current_history_id()
# upload a nested collection
self.dataset_collection_populator.create_list_of_list_in_history(
history_id,
collection_type="list:list",
wait=True,
).json()["id"]
self.tool_open("identifier_multiple")
self.components.tool_form.parameter_data_input_collection(parameter="input1").wait_for_and_click()
self.sleep_for(self.wait_types.UX_RENDER)
select_field = self.components.tool_form.parameter_data_select(parameter="input1")
self.select_set_value(select_field, "list:list")
self.sleep_for(self.wait_types.UX_RENDER)
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(7)
self.history_panel_expand_collection(7)
self.sleep_for(self.wait_types.UX_RENDER)
self.history_panel_click_item_title(1)
self.sleep_for(self.wait_types.UX_RENDER)
self.hda_click_primary_action_button(1, "rerun")
self.sleep_for(self.wait_types.UX_RENDER)
self.tool_form_execute()
self.components.history_panel.collection_view.back_to_history.wait_for_and_click()
self.history_panel_wait_for_hid_ok(9)
[docs] @selenium_test
@flakey
def test_run_data(self):
test_path = self.get_filename("1.fasta")
test_path_decoy = self.get_filename("1.txt")
# Upload form posts bad data if executed two times in a row like this, so
# wait between uploads. xref https://github.com/galaxyproject/galaxy/issues/5169
self.perform_upload(test_path)
self.history_panel_wait_for_hid_ok(1)
self.perform_upload(test_path_decoy)
self.history_panel_wait_for_hid_ok(2)
self.home()
self.tool_open("head")
self.tool_set_value("input", "1.fasta", expected_type="data")
self.screenshot("tool_form_simple_data")
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(3)
latest_hda = self.latest_history_item()
assert latest_hda["hid"] == 3
assert latest_hda["name"] == "Select first on data 1"
[docs] @selenium_test
def test_bibtex_rendering(self):
self.home()
# prefetch citations so they will be available quickly when rendering tool form.
citations_api = self.api_get("tools/bibtex/citations")
citation_count = len(citations_api)
self.tool_open("bibtex")
self.components.tool_form.about.wait_for_and_click()
@retry_assertion_during_transitions
def assert_citations_visible():
references = self.components.tool_form.reference.all()
if (references_rendered := len(references)) != citation_count:
citations_api = self.api_get("tools/bibtex/citations")
current_citation_count = len(citations_api)
message = f"Expected {citation_count} references to be rendered, {references_rendered} actually rendered. Currently the API yields {current_citation_count} references"
raise AssertionError(message)
return references
references = assert_citations_visible()
doi_resolved_citation = references[0]
assert "platform for interactive" in doi_resolved_citation.text
self.screenshot("tool_form_citations_formatted")
def _check_dataset_details_for_inttest_value(self, hid, expected_value="42"):
tds = self._get_dataset_tool_parameters(hid)
assert tds
assert any(expected_value in td.text for td in tds)
def _get_dataset_tool_parameters(self, hid):
self.hda_click_details(hid)
self.components.dataset_details._.wait_for_visible()
tool_parameters_table = self.components.dataset_details.tool_parameters.wait_for_visible()
tbody_element = tool_parameters_table.find_element(By.CSS_SELECTOR, "tbody")
tds = tbody_element.find_elements(By.CSS_SELECTOR, "td")
return tds
def _run_environment_test_tool(self, inttest_value="42"):
self.home()
self.tool_open("environment_variables")
self.tool_set_value("inttest", inttest_value)
self.tool_form_execute()
[docs]class TestLoggedInToolForm(SeleniumTestCase):
ensure_registered = True
[docs] @selenium_test
def test_dataset_state_filtering(self):
# upload an ok (HID 1) and a discarded (HID 2) dataset and run a tool
# normally HID 2 would be selected but since it is discarded - it won't
# be an option so verify the result was run with HID 1.
test_path = self.get_filename("1.fasta")
self.perform_upload(test_path)
self.history_panel_wait_for_hid_ok(1)
history_id = self.current_history_id()
self.dataset_populator.create_contents_from_store(
history_id,
store_dict=one_hda_model_store_dict(include_source=False),
)
self.home()
self.tool_open("head")
self.components.tool_form.execute.wait_for_visible()
self.screenshot("tool_form_with_filtered_discarded_input")
self.tool_form_execute()
self.history_panel_wait_for_hid_ok(3)
latest_hda = self.latest_history_item()
assert latest_hda["hid"] == 3
assert latest_hda["name"] == "Select first on data 1"
[docs] @selenium_test
def test_run_apply_rules_1(self):
self._apply_rules_and_check(rules_test_data.EXAMPLE_1)
self.screenshot("tool_apply_rules_example_1_final")
[docs] @selenium_test
def test_run_apply_rules_2(self):
self._apply_rules_and_check(rules_test_data.EXAMPLE_2)
self.screenshot("tool_apply_rules_example_2_final")
[docs] @selenium_test
def test_run_apply_rules_3(self):
self._apply_rules_and_check(rules_test_data.EXAMPLE_3)
self.screenshot("tool_apply_rules_example_3_final")
[docs] @selenium_test
def test_run_apply_rules_4(self):
self._apply_rules_and_check(rules_test_data.EXAMPLE_4)
self.screenshot("tool_apply_rules_example_4_final")
[docs] @selenium_test
@managed_history
@skip_if_github_down
@pytest.mark.gtn_screenshot
@pytest.mark.local
def test_run_apply_rules_tutorial(self):
self.home()
self.upload_rule_start()
self.upload_rule_set_data_type("Collections")
self.components.upload.rule_source_content.wait_for_and_send_keys(
"""https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/treated1fb.txt treated_single_1
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/treated2fb.txt treated_paired_2
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/treated3fb.txt treated_paired_3
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/untreated1fb.txt untreated_single_4
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/untreated2fb.txt untreated_single_5
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/untreated3fb.txt untreated_paired_6
https://raw.githubusercontent.com/jmchilton/galaxy/apply_rules_tutorials/test-data/rules/untreated4fb.txt untreated_paired_7
"""
)
self.screenshot("rules_apply_rules_example_4_1_input_paste")
self.upload_rule_build()
rule_builder = self.components.rule_builder
rule_builder._.wait_for_and_click()
self.rule_builder_set_mapping("url", "A")
self.rule_builder_set_mapping("list-identifiers", ["B"])
self.rule_builder_set_collection_name("flat_count_list")
self.rule_builder_set_extension("txt")
self.screenshot("rules_apply_rules_example_4_2_input_rules")
rule_builder.main_button_ok.wait_for_and_click()
self.history_panel_wait_for_hid_ok(1)
self.screenshot("rules_apply_rules_example_4_3_input_ready")
self.history_multi_view_display_collection_contents(1, "list")
self.screenshot("rules_apply_rules_example_4_4_input_list")
self.home()
add_depth_rules = {
"rules": [
{
"type": "add_column_metadata",
"value": "identifier0",
},
{"type": "add_column_regex", "target_column": 0, "expression": "(.*)_(.*)_.*", "group_count": 2},
],
"mapping": [
{
"type": "list_identifiers",
"columns": [1, 2, 0],
}
],
}
self._tool_apply_with_source(
add_depth_rules,
hid=1,
landing_screenshot="rules_apply_rules_example_4_5_apply_rules_landing",
rule_init_screenshot="rules_apply_rules_example_4_6_apply_rules_init_flat",
rule_complete_screenshot="rules_apply_rules_example_4_7_apply_rules_add_depth",
)
self.history_panel_wait_for_hid_ok(16)
self.history_multi_view_display_collection_contents(16, "list:list:list")
self.screenshot("rules_apply_rules_example_4_8_nested")
self.home()
invert_rules = {
"rules": [
{
"type": "add_column_metadata",
"value": "identifier0",
},
{
"type": "add_column_metadata",
"value": "identifier1",
},
{
"type": "add_column_metadata",
"value": "identifier2",
},
],
"mapping": [
{
"type": "list_identifiers",
"columns": [1, 0, 2],
}
],
}
self._tool_apply_with_source(
invert_rules,
rule_init_screenshot="rules_apply_rules_example_4_9_apply_rules_init_nested",
rule_complete_screenshot="rules_apply_rules_example_4_10_apply_rules_inverted",
)
self.history_panel_wait_for_hid_ok(24)
self.history_multi_view_display_collection_contents(24, "list:list:list")
self.screenshot("rules_apply_rules_example_4_11_inverted")
self.home()
filter_rules = {
"rules": [
{
"type": "add_column_metadata",
"value": "identifier0",
},
{
"type": "add_filter_regex",
"target_column": 0,
"expression": ".*_single_.*",
"invert": False,
},
],
"mapping": [
{
"type": "list_identifiers",
"columns": [0],
}
],
}
self._tool_apply_with_source(
filter_rules, hid=1, rule_complete_screenshot="rules_apply_rules_example_4_12_apply_rules_filter"
)
self.history_panel_wait_for_hid_ok(28)
self.history_multi_view_display_collection_contents(28, "list")
self.screenshot("rules_apply_rules_example_4_13_filtered")
self.home()
filter_and_nest_rules = {
"rules": [
{
"type": "add_column_metadata",
"value": "identifier0",
},
{
"type": "add_filter_regex",
"target_column": 0,
"expression": ".*_single_.*",
"invert": False,
},
{"type": "add_column_regex", "target_column": 0, "expression": "(.*)_single_.*", "group_count": 1},
],
"mapping": [
{
"type": "list_identifiers",
"columns": [1, 0],
}
],
}
self._tool_apply_with_source(
filter_and_nest_rules,
hid=1,
rule_complete_screenshot="rules_apply_rules_example_4_14_apply_rules_filtered_and_nested",
)
self.history_panel_wait_for_hid_ok(32)
self.history_multi_view_display_collection_contents(32, "list:list")
self.screenshot("rules_apply_rules_example_4_15_filtered_and_nested")
def _apply_rules_and_check(self, example: Dict[str, Any]) -> None:
rule_builder = self.components.rule_builder
self.home()
history_id = self.current_history_id()
stage_rules_example(self.api_interactor_for_logged_in_user(), history_id, example)
self.dataset_populator.wait_for_history(history_id)
self.home()
self._tool_open_apply_rules()
self.screenshot("tool_apply_rules_landing")
self.tool_parameter_edit_rules()
rule_builder._.wait_for_visible()
self.screenshot("tool_apply_rules_builder_landing")
self.rule_builder_set_source(json.dumps(example["rules"]))
self.screenshot("tool_apply_rules_after")
rule_builder.main_button_ok.wait_for_and_click()
self.tool_form_execute()
output_hid = example["output_hid"]
self.home()
self.history_panel_wait_for_hid_ok(output_hid)
output_hdca = self.dataset_populator.get_history_collection_details(history_id, hid=output_hid, wait=False)
example["check"](output_hdca, self.dataset_populator)
def _tool_apply_with_source(
self, rules_json, hid=None, landing_screenshot=None, rule_init_screenshot=None, rule_complete_screenshot=None
):
self._tool_open_apply_rules()
if hid:
self.tool_set_value("input", f"{hid}:", expected_type="data_collection")
if landing_screenshot:
self.screenshot(landing_screenshot)
rule_builder = self.components.rule_builder
self.tool_parameter_edit_rules()
rule_builder._.wait_for_visible()
if rule_init_screenshot:
self.screenshot(rule_init_screenshot)
self.rule_builder_set_source(json.dumps(rules_json))
if rule_complete_screenshot:
self.screenshot(rule_complete_screenshot)
rule_builder.main_button_ok.wait_for_and_click()
self.tool_form_execute()
def _tool_open_apply_rules(self):
self.tool_open("__APPLY_RULES__", outer=True) # may appear twice in panel, grab top-level link