Merge pull request #10755 from mvdbeek/selenium_annotation_fix

Fix currently failing selenium tests, move to github workflow
This commit is contained in:
John Chilton
2020-11-22 14:48:27 -05:00
committed by GitHub
17 changed files with 117 additions and 46 deletions
+43
View File
@@ -0,0 +1,43 @@
name: Selenium tests
on: [push, pull_request]
env:
GALAXY_TEST_DBURI: 'postgres://postgres:postgres@localhost:5432/galaxy?client_encoding=utf8'
GALAXY_TEST_SKIP_FLAKEY_TESTS_ON_ERROR: 'true'
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7']
chunk: [0, 1, 2]
services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
steps:
- uses: actions/checkout@v2
with:
path: 'galaxy root'
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip dir
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: pip-cache-${{ matrix.python-version }}-${{ hashFiles('galaxy root/requirements.txt') }}
- uses: nanasess/setup-chromedriver@master
- name: Run tests
run: ./run_tests.sh -selenium lib/galaxy_test/selenium -- --num-shards=3 --shard-id=${{ matrix.chunk }}
working-directory: 'galaxy root'
- uses: actions/upload-artifact@v2
if: failure()
with:
name: Selenium test results
path: 'galaxy root/database/test_errors'
+8 -2
View File
@@ -11,10 +11,16 @@
<b-button type="submit" variant="primary" @click="setUsername()">Set Username</b-button>
</div>
<div v-else>
<b-form-checkbox switch v-model="item.importable" @change="onImportable">
<b-form-checkbox switch class="make-accessible" v-model="item.importable" @change="onImportable">
Make {{ model_class }} accessible.
</b-form-checkbox>
<b-form-checkbox v-if="item.importable" switch v-model="item.published" @change="onPublish">
<b-form-checkbox
v-if="item.importable"
class="make-publishable"
switch
v-model="item.published"
@change="onPublish"
>
Make {{ model_class }} publicly available in
<a :href="published_url" target="_top">Published {{ plural_name }}</a> section.
</b-form-checkbox>
+6 -1
View File
@@ -1,7 +1,11 @@
<template>
<div class="tool-footer">
<!-- <b-button v-b-toggle.collapse-about>About this tool</b-button> -->
<b-link :aria-expanded="expanded" aria-controls="collapse-about" @click="expanded = !expanded"
<b-link
:aria-expanded="expanded"
aria-controls="collapse-about"
class="collapse-about"
@click="expanded = !expanded"
>About this tool
<font-awesome-icon :icon="expanded ? 'angle-double-up' : 'angle-double-down'" />
</b-link>
@@ -17,6 +21,7 @@
@click="copyBibtex"
/>
<Citation
class="formatted-reference"
v-for="(citation, index) in citations"
:key="index"
:citation="citation"
@@ -27,7 +27,7 @@
<div id="workflow-annotation-area" class="mt-2">
<b>Annotation</b>
<meta itemprop="description" :content="annotation" />
<b-textarea id="workflow-annotation" :value="annotation" @change="onAnnotation" />
<b-textarea id="workflow-annotation" :value="annotation" @input="onAnnotation" />
<div class="form-text text-muted">
These notes will be visible when this workflow is viewed.
</div>
@@ -165,7 +165,12 @@ export default {
this.onAttributes({ tags });
},
onAnnotation(annotation) {
this.onAttributes({ annotation });
if (this.annotationTimeout) {
clearTimeout(this.annotationTimeout);
}
this.annotationTimeout = setTimeout(() => {
this.onAttributes({ annotation });
}, 300);
},
onRename(name) {
this.onAttributes({ name });
@@ -193,6 +198,9 @@ export default {
this.onError(error);
});
},
beforeDestroy: function () {
clearTimeout(this.annotationTimeout);
},
},
};
</script>
@@ -292,6 +292,22 @@ export default {
this.$emit("onActivate", this);
});
},
setAnnotation(annotation) {
if (this.annotationTimeout) {
clearTimeout(this.annotationTimeout);
}
this.annotationTimeout = setTimeout(() => {
this.annotation = annotation;
}, 100);
},
setLabel(label) {
if (this.labelTimeout) {
clearTimeout(this.labelTimeout);
}
this.labelTimeout = setTimeout(() => {
this.label = label;
}, 100);
},
setData(data) {
this.config_form = data.config_form;
this.tool_state = data.tool_state;
@@ -116,10 +116,13 @@ function _addLabelAnnotation(self, node) {
inputs.unshift({
type: "text",
name: "__annotation",
label: "Annotation",
label: "Step Annotation",
fixed: true,
value: node.annotation,
area: true,
onchange: function (new_annotation) {
node.setAnnotation(new_annotation);
},
help: "Add an annotation or notes to this step. Annotations are available when a workflow is viewed.",
});
inputs.unshift({
@@ -130,6 +133,7 @@ function _addLabelAnnotation(self, node) {
help: _l("Add a step label."),
fixed: true,
onchange: function (new_label) {
node.setLabel(new_label);
let duplicate = false;
for (const i in workflow.nodes) {
const n = workflow.nodes[i];
@@ -145,7 +149,6 @@ function _addLabelAnnotation(self, node) {
"error_text",
duplicate && "Duplicate label. Please fix this before saving the workflow."
);
self.form.trigger("change");
},
});
}
@@ -19,6 +19,7 @@ pytest-html = "*"
pytest-mock = "*"
pytest-pythonpath = "*"
pytest-postgresql = "*"
pytest-shard = "*"
recommonmark = "*"
responses = "*"
selenium = "*"
@@ -45,6 +45,7 @@ pytest-metadata==1.10.0; python_version >= '2.7' and python_version not in '3.0,
pytest-mock==3.3.1
pytest-postgresql==2.5.2
pytest-pythonpath==0.7.3
pytest-shard==0.1.1
pytest==6.1.2
python-irodsclient==0.8.5
pytz==2020.4
+1 -1
View File
@@ -113,7 +113,7 @@ def get_item_annotation_obj(db_session, user, item):
# Get annotation association class.
annotation_assoc_class = _get_annotation_assoc_class(item)
if not annotation_assoc_class:
if not annotation_assoc_class or item.id is None:
return None
# Get annotation association object.
+4
View File
@@ -216,6 +216,10 @@ class NavigatesGalaxy(HasDriver):
def history_panel_name(self):
return self.history_panel_name_element().text
def make_accessible_and_publishable(self):
self.components.histories.sharing.make_accessible.wait_for_and_click()
self.components.histories.sharing.make_publishable.wait_for_and_click()
def history_contents(self, history_id=None, view='summary', datasets_only=True):
if history_id is None:
history_id = self.current_history_id()
+4 -6
View File
@@ -286,7 +286,8 @@ histories:
selectors:
unshare_user_button: '.unshare_user'
share_with_a_user_button: '#share_with_a_user'
make_accessible_and_publish: '#make_accessible_and_publish'
make_accessible: '.make-accessible label'
make_publishable: '.make-publishable label'
labels:
unshare: 'Unshare'
@@ -326,11 +327,8 @@ tool_form:
options: '#options [data-toggle="dropdown"]'
execute: 'button#execute'
parameter_div: 'div.ui-form-element[tour_id="${parameter}"]'
citations: '.citations-formatted'
reference: '.citations-formatted .formatted-reference'
show_bibtex:
type: xpath
selector: '//a[@class="nav-link" and text()="BibTeX"]'
reference: '.formatted-reference'
about: '.collapse-about'
labels:
generate_tour: 'Generate Tour'
+4 -6
View File
@@ -1,6 +1,6 @@
"""Utilities for using sizzle (jQuery-style) selectors with Selenium."""
import re
import json
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait
@@ -119,11 +119,9 @@ def _is_sizzle_loaded(driver):
def _make_sizzle_string(sizzle_selector):
try:
selector = sizzle_selector.decode("utf-8")
except (AttributeError, UnicodeEncodeError):
selector = sizzle_selector
return "return Sizzle(\"{selector}\");".format(selector=re.escape(selector))
# Use json.dumps to escape quotes
selector = json.dumps(sizzle_selector)
return f"return Sizzle({selector});"
__all__ = (
@@ -43,7 +43,7 @@ class SavedHistoriesTestCase(SharedStateSeleniumTestCase):
# Publish the history
self.click_grid_popup_option(self.history2_name, 'Share or Publish')
self.components.histories.sharing.make_accessible_and_publish.wait_for_and_click()
self.make_accessible_and_publishable()
self.navigate_to_histories_page()
@@ -199,8 +199,7 @@ class HistoryGridTestCase(SharedStateSeleniumTestCase):
def publish_current_history(self):
self.click_history_option('Share or Publish')
self.components.histories.sharing.make_accessible_and_publish.wait_for_and_click()
self.wait_for_selector_clickable('#disable_link_access_and_unpublish')
self.make_accessible_and_publishable()
def navigate_to_published_histories_page(self):
self.home()
+1 -7
View File
@@ -124,7 +124,7 @@ class ToolFormTestCase(SeleniumTestCase, UsesHistoryItemAssertions):
citations_api = self.api_get("tools/bibtex/citations")
assert len(citations_api) == 29, len(citations_api)
self.tool_open("bibtex")
self.components.tool_form.citations.wait_for_visible()
self.components.tool_form.about.wait_for_and_click()
@retry_assertion_during_transitions
def assert_citations_visible():
@@ -138,12 +138,6 @@ class ToolFormTestCase(SeleniumTestCase, UsesHistoryItemAssertions):
assert "Galaxy: A platform for interactive" in doi_resolved_citation.text
self.screenshot("tool_form_citations_formatted")
self.components.tool_form.show_bibtex.wait_for_and_click()
references = assert_citations_visible()
r0text = references[0].text
assert "@article{Giardine_2005" in r0text
self.screenshot("tool_form_citations_bibtex")
def _check_dataset_details_for_inttest_value(self, hid, expected_value="42"):
self.hda_click_primary_action_button(hid, "info")
@@ -63,9 +63,6 @@ class WorkflowEditorTestCase(SeleniumTestCase):
editor.label_input.wait_for_and_send_keys("input1")
editor.annotation_input.wait_for_and_send_keys("my cool annotation")
self.sleep_for(self.wait_types.UX_RENDER)
self.screenshot("workflow_editor_data_input_filled_in PRECLICK")
editor.label_input.wait_for_and_click() # Seems to help force the save of whole annotation.
self.sleep_for(self.wait_types.UX_RENDER)
self.screenshot("workflow_editor_data_input_filled_in")
self.workflow_editor_click_save()
@@ -75,7 +72,7 @@ class WorkflowEditorTestCase(SeleniumTestCase):
label = editor.label_input.wait_for_value()
assert label == "input1", label
annotation = editor.annotation_input.wait_for_value()
assert annotation == "my cool annotation"
assert annotation == "my cool annotation", annotation
data_input_node.destroy.wait_for_and_click()
data_input_node.wait_for_absent()
self.screenshot("workflow_editor_data_input_deleted")
@@ -89,7 +86,6 @@ class WorkflowEditorTestCase(SeleniumTestCase):
self.screenshot("workflow_editor_data_collection_input_new")
editor.label_input.wait_for_and_send_keys("input1")
editor.annotation_input.wait_for_and_send_keys("my cool annotation")
editor.label_input.wait_for_and_click() # Seems to help force the save of whole annotation.
self.sleep_for(self.wait_types.UX_RENDER)
self.screenshot("workflow_editor_data_collection_input_filled_in")
self.workflow_editor_click_save()
@@ -100,7 +96,7 @@ class WorkflowEditorTestCase(SeleniumTestCase):
label = editor.label_input.wait_for_value()
assert label == "input1", label
annotation = editor.annotation_input.wait_for_value()
assert annotation == "my cool annotation"
assert annotation == "my cool annotation", annotation
data_input_node.destroy.wait_for_and_click()
data_input_node.wait_for_absent()
self.sleep_for(self.wait_types.UX_RENDER)
@@ -115,7 +111,6 @@ class WorkflowEditorTestCase(SeleniumTestCase):
self.screenshot("workflow_editor_parameter_input_new")
editor.label_input.wait_for_and_send_keys("input1")
editor.annotation_input.wait_for_and_send_keys("my cool annotation")
editor.label_input.wait_for_and_click() # Seems to help force the save of whole annotation.
self.sleep_for(self.wait_types.UX_RENDER)
self.screenshot("workflow_editor_parameter_input_filled_in")
self.workflow_editor_click_save()
@@ -126,7 +121,7 @@ class WorkflowEditorTestCase(SeleniumTestCase):
label = editor.label_input.wait_for_value()
assert label == "input1", label
annotation = editor.annotation_input.wait_for_value()
assert annotation == "my cool annotation"
assert annotation == "my cool annotation", annotation
data_input_node.destroy.wait_for_and_click()
data_input_node.wait_for_absent()
self.sleep_for(self.wait_types.UX_RENDER)
@@ -146,16 +141,16 @@ steps:
inttest: input_int
""")
self.screenshot("workflow_editor_parameter_connection_simple")
self.assert_connected("input_int#output", "simple_constructs#inttest")
self.assert_connected("input_int#output", "tool_exec#inttest")
editor = self.components.workflow_editor
tool_node = editor.node._(label="simple_constructs")
tool_node = editor.node._(label="tool_exec")
tool_input = tool_node.input_terminal(name="inttest")
tool_input.wait_for_and_click()
editor.connector_destroy_callout.wait_for_and_click()
self.assert_not_connected("input_int#output", "simple_constructs#inttest")
self.assert_not_connected("input_int#output", "tool_exec#inttest")
self.screenshot("workflow_editor_parameter_connection_destroyed")
# When connected, cannot turn it into a RuntimeValue..
@@ -177,8 +172,8 @@ steps:
tool_input.wait_for_visible()
collapse_input.wait_for_absent_or_hidden()
self.workflow_editor_connect("input_int#output", "simple_constructs#inttest", screenshot_partial="workflow_editor_parameter_connection_dragging")
self.assert_connected("input_int#output", "simple_constructs#inttest")
self.workflow_editor_connect("input_int#output", "tool_exec#inttest", screenshot_partial="workflow_editor_parameter_connection_dragging")
self.assert_connected("input_int#output", "tool_exec#inttest")
@selenium_test
def test_existing_connections(self):
+3 -3
View File
@@ -393,7 +393,7 @@ do
;;
-selenium|--selenium)
GALAXY_TEST_TOOL_CONF="lib/galaxy/config/sample/tool_conf.xml.sample,test/functional/tools/samples_tool_conf.xml"
test_script="./scripts/functional_tests.py"
test_script="pytest"
report_file="./run_selenium_tests.html"
skip_client_build=""
selenium_test=1;
@@ -617,8 +617,8 @@ setup_python
if [ -n "$framework_test" -o -n "$installed_test" -o -n "$migrated_test" -o -n "$data_managers_test" ] ; then
[ -n "$test_id" ] && selector="-k $test_id" || selector=""
extra_args="test/functional/test_toolbox_pytest.py $selector $marker"
elif [ -n "$selenium_test" ] ; then
extra_args="$selenium_script -selenium"
elif [ -n "$selenium_script" ]; then
extra_args="$selenium_script"
elif [ -n "$toolshed_script" ]; then
extra_args="$toolshed_script"
elif [ -n "$api_script" ]; then