Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[21.01] Selenium tests for 21.01 history import and export UIs. #11152

Merged
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
3 changes: 2 additions & 1 deletion client/src/components/FilesDialog/FilesInput.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<b-form-input v-model="localValue" :placeholder="placeholder" @click="selectFile"> </b-form-input>
<b-form-input class="directory-form-input" v-model="localValue" :placeholder="placeholder" @click="selectFile">
</b-form-input>
</template>

<script>
Expand Down
7 changes: 4 additions & 3 deletions client/src/components/HistoryExport/ExportLink.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
<template>
<span>
<b
><a :href="link">{{ link }}</a></b
><a class="generated-export-link" :href="link">{{ link }}</a></b
>
<font-awesome-icon
v-b-tooltip.hover
title="Copy export URL to your clipboard"
class="copy-export-link"
icon="link"
style="cursor: pointer;"
@click="copyUrl"
/>
<i
title="Information about when the history export was generated is included in the job details. Additionally, if there are issues with export, the job details may help figure out the underlying problem or communicate issues to your Galaxy administrator."
>
(<a href="#" @click="showDetails">view job details</a>)
(<a class="show-job-link" href="#" @click="showDetails">view job details</a>)
</i>
<b-modal v-model="details" scrollable ok-only>
<b-modal v-model="details" modal-class="job-information-modal" scrollable ok-only hide-header>
<job-information :job_id="historyExport.job_id" :include-times="true" />
</b-modal>
</span>
Expand Down
10 changes: 6 additions & 4 deletions client/src/components/HistoryExport/Index.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<template>
<span>
<span class="history-export-component">
<h2>Export history archive</h2>
<span v-if="initializing">
<loading-span message="Loading server configuration." />
</span>
<span v-else-if="hasWritableFileSources">
<b-card no-body>
<b-tabs pills card vertical>
<b-tab title="to a link" active>
<b-tab title="to a link" title-link-class="tab-export-to-link" active>
<b-card-text>
<ToLink :history-id="historyId" />
</b-card-text>
</b-tab>
<b-tab title="to a remote file">
<ToRemoteFile :history-id="historyId" />
<b-tab title="to a remote file" title-link-class="tab-export-to-file">
<b-card-text>
<ToRemoteFile :history-id="historyId" />
</b-card-text>
</b-tab>
</b-tabs>
</b-card>
Expand Down
8 changes: 4 additions & 4 deletions client/src/components/HistoryExport/ToRemoteFile.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>
<div class="export-to-remote-file">
<b-alert v-if="errorMessage" show variant="danger" dismissible @dismissed="errorMessage = null">
{{ errorMessage }}
<JobError
Expand All @@ -20,14 +20,14 @@
</div>
<div v-else>
<b-form-group
id="directory"
id="fieldset-directory"
label-for="directory"
description="Select a 'remote files' directory to export history archive to."
class="mt-3"
>
<files-input v-model="directory" mode="directory" :requireWritable="true" />
<files-input id="directory" v-model="directory" mode="directory" :requireWritable="true" />
</b-form-group>
<b-form-group id="name" label-for="name" description="Give the exported file a name." class="mt-3">
<b-form-group id="fieldset-name" label-for="name" description="Give the exported file a name." class="mt-3">
<b-form-input id="name" v-model="name" placeholder="Name" required></b-form-input>
</b-form-group>
<b-row align-h="end">
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/HistoryImport.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<b-card title="Import a history from an archive">
<b-card body-class="history-import-component" title="Import a history from an archive">
<b-alert v-if="errorMessage" variant="danger" dismissible @dismissed="errorMessage = null" show>
{{ errorMessage }}
<JobError
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/JobInformation/JobError.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</div>
<!-- TODO: modal for reporting error. -->
</b-card-text>
<b-modal v-model="showInfo" scrollable ok-only>
<b-modal v-model="showInfo" modal-class="job-information-modal" scrollable ok-only hide-header>
<job-information :job_id="job.id" :include-times="true" />
</b-modal>
</b-card>
Expand Down
38 changes: 36 additions & 2 deletions lib/galaxy/selenium/navigates_galaxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,14 +517,24 @@ def click_center(self):
center_element = self.driver.find_element_by_css_selector("#center")
action_chains.move_to_element(center_element).click().perform()

def perform_upload(self, test_path, ext=None, genome=None, ext_all=None, genome_all=None):
def perform_upload(self, test_path, **kwd):
self._perform_upload(test_path=test_path, **kwd)

def perform_upload_of_pasted_content(self, paste_data, **kwd):
self._perform_upload(paste_data=paste_data, **kwd)

def _perform_upload(self, test_path=None, paste_data=None, ext=None, genome=None, ext_all=None, genome_all=None):
self.home()
self.upload_start_click()

self.upload_set_footer_extension(ext_all)
self.upload_set_footer_genome(genome_all)

self.upload_queue_local_file(test_path)
if test_path:
self.upload_queue_local_file(test_path)
else:
assert paste_data is not None
self.upload_paste_data(paste_data)

if ext is not None:
self.wait_for_selector_visible('.upload-extension')
Expand Down Expand Up @@ -635,6 +645,13 @@ def upload_queue_local_file(self, test_path, tab_id="regular"):
file_upload = self.wait_for_selector('div#%s input[type="file"]' % tab_id)
file_upload.send_keys(test_path)

def upload_paste_data(self, pasted_content, tab_id="regular"):
tab_locator = f"div#{tab_id}"
self.wait_for_and_click_selector(f"{tab_locator} button#btn-new")

textarea = self.wait_for_selector(f"{tab_locator} .upload-text-content")
textarea.send_keys(pasted_content)

def upload_rule_start(self):
self.upload_start_click()
self.upload_tab_click("rule-based")
Expand Down Expand Up @@ -865,6 +882,11 @@ def workflow_editor_click_save(self):
self.wait_for_and_click_selector("#workflow-save-button")
self.sleep_for(self.wait_types.DATABASE_OPERATION)

def navigate_to_histories_page(self):
self.home()
self.click_masthead_user()
self.components.masthead.histories.wait_for_and_click()

def navigate_to_user_preferences(self):
self.home()
self.click_masthead_user()
Expand Down Expand Up @@ -1164,6 +1186,18 @@ def histories_click_advanced_search(self):
search_selector = '#standard-search .advanced-search-toggle'
self.wait_for_and_click_selector(search_selector)

@retry_during_transitions
def histories_get_history_names(self):
self.sleep_for(self.wait_types.UX_RENDER)
names = []
grid = self.wait_for_selector('#grid-table-body')
for row in grid.find_elements_by_tag_name('tr'):
td = row.find_elements_by_tag_name('td')
name = td[1].text if td[0].text == '' else td[0].text
if name != "No items" and not name.startswith("No matching entries found"):
names.append(name)
return names

def history_panel_add_tags(self, tags):
tag_icon_selector = self.components.history_panel.tag_icon
tag_area_selector = self.components.history_panel.tag_area
Expand Down
33 changes: 33 additions & 0 deletions lib/galaxy/selenium/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ history_panel:
options_show_history_structure:
type: xpath
selector: '//a[text()="Show Structure"]'
options_show_export_history_to_file:
type: xpath
selector: '//a[text()="Export History to File"]'
new_history_button: '#history-new-button'
multi_view_button: '#history-view-multi-button'

Expand Down Expand Up @@ -282,6 +285,9 @@ collection_builders:
reverse_datasets: ".reverse-column .column-datasets"

histories:
labels:
import_button: 'Import from file'

sharing:
selectors:
unshare_user_button: '.unshare_user'
Expand All @@ -291,6 +297,33 @@ histories:
labels:
unshare: 'Unshare'

files_dialog:
selectors:
ftp_row: 'span[title="gxftp://"]'
row: 'span[title="${uri}"]'

history_export:
selectors:
export_link: '.export-link'
running: '.history-export-component .loading-icon'
generated_export_link: '.generated-export-link'
copy_export_link: '.copy-export-link'
show_job_link: '.show-job-link'
job_table: '.info_data_table'
job_table_ok: '.job-information-modal .btn-primary'
tab_export_to_file: '.tab-export-to-file'
directory_input: '.directory-form-input'
name_input: '.export-to-remote-file #name'
export_button: '.export-button'
success_message: '.history-export-component .alert-success'

history_import:
selectors:
radio_button_remote_files: '.history-import-component .fa-folder-open'
import_button: '.import-button'
running: '.history-import-component .loading-icon'
success_message: '.history-import-component .alert-success'

pages:
selectors:
create: '.manage-table-actions .action-button'
Expand Down
17 changes: 1 addition & 16 deletions lib/galaxy_test/selenium/test_histories_list.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from .framework import (
retry_assertion_during_transitions,
retry_during_transitions,
selenium_test,
SharedStateSeleniumTestCase,
)
Expand Down Expand Up @@ -251,17 +250,8 @@ def assert_histories_in_grid(self, expected_histories, present=True):
else:
self.assertEqual(intersection, set())

@retry_during_transitions
def get_histories(self):
self.sleep_for(self.wait_types.UX_RENDER)
names = []
grid = self.wait_for_selector('#grid-table-body')
for row in grid.find_elements_by_tag_name('tr'):
td = row.find_elements_by_tag_name('td')
name = td[1].text if td[0].text == '' else td[0].text
if name != "No items" and not name.startswith("No matching entries found"):
names.append(name)
return names
return self.histories_get_history_names()

def set_filter(self, selector, value):
filter_input = self.wait_for_selector_clickable(selector)
Expand All @@ -275,11 +265,6 @@ def unset_filter(self, filter_key, filter_value):
self.wait_for_and_click_selector(close_button_selector)
self.sleep_for(self.wait_types.UX_RENDER)

def navigate_to_histories_page(self):
self.home()
self.click_masthead_user() # Open masthead menu
self.components.masthead.histories.wait_for_and_click()

def setup_shared_state(self):
SavedHistoriesTestCase.user_email = self._get_random_email()
SavedHistoriesTestCase.history1_name = self._get_random_name()
Expand Down
44 changes: 44 additions & 0 deletions lib/galaxy_test/selenium/test_history_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from .framework import (
selenium_test,
SeleniumTestCase
)


class HistoryExportTestCase(SeleniumTestCase):
ensure_registered = True

@selenium_test
def test_history_export(self):
gx_selenium_context = self
gx_selenium_context.perform_upload_of_pasted_content("my cool content")
gx_selenium_context.history_panel_wait_for_hid_ok(1)
gx_selenium_context.click_history_options()
gx_selenium_context.components.history_panel.options_show_export_history_to_file.wait_for_and_click()
history_export = gx_selenium_context.components.history_export
history_export.export_link.wait_for_and_click()
history_export.running.wait_for_visible()
history_export.running.wait_for_absent(wait_type=gx_selenium_context.wait_types.JOB_COMPLETION)
history_export.generated_export_link.wait_for_visible()
history_export.copy_export_link.wait_for_visible()
history_export.job_table.assert_absent_or_hidden()
history_export.show_job_link.wait_for_and_click()
history_export.job_table.wait_for_present()
history_export.job_table_ok.wait_for_and_click()
history_export.job_table.wait_for_absent()

gx_selenium_context.click_history_options()
gx_selenium_context.components.history_panel.options_show_export_history_to_file.wait_for_and_click()

# this time the exported link is still there
history_export.generated_export_link.wait_for_visible()
history_export.export_link.assert_absent()

gx_selenium_context.perform_upload_of_pasted_content("my cool content part 2")
gx_selenium_context.history_panel_wait_for_hid_ok(2)

gx_selenium_context.click_history_options()
gx_selenium_context.components.history_panel.options_show_export_history_to_file.wait_for_and_click()

# now we have a generated link and a link to update to the newest export
history_export.generated_export_link.wait_for_visible()
history_export.export_link.wait_for_visible()
65 changes: 65 additions & 0 deletions test/integration_selenium/test_history_import_export_ftp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import os

from .framework import (
selenium_test,
SeleniumIntegrationTestCase
)


class HistoryImportExportFtpSeleniumIntegrationTestCase(SeleniumIntegrationTestCase):
ensure_registered = True

@classmethod
def handle_galaxy_config_kwds(cls, config):
ftp_dir = cls.ftp_dir()
os.makedirs(ftp_dir)
config["ftp_upload_dir"] = ftp_dir
config["ftp_upload_site"] = "ftp://ftp.galaxyproject.com"

@classmethod
def ftp_dir(cls):
return cls.temp_config_dir("ftp")

@selenium_test
def test_history_import_export(self):
email = self.get_logged_in_user()["email"]
user_ftp_dir = os.path.join(self.ftp_dir(), email)
os.makedirs(user_ftp_dir)

gx_selenium_context = self
gx_selenium_context.perform_upload_of_pasted_content("my cool content")
gx_selenium_context.history_panel_wait_for_hid_ok(1)
gx_selenium_context.click_history_options()
gx_selenium_context.components.history_panel.options_show_export_history_to_file.wait_for_and_click()
history_export = gx_selenium_context.components.history_export
files_dialog = gx_selenium_context.components.files_dialog

# we land on link version, but go to export to file
history_export.export_link.wait_for_visible()
history_export.tab_export_to_file.wait_for_and_click()
history_export.export_link.wait_for_absent_or_hidden()
history_export.directory_input.wait_for_and_click()
files_dialog.ftp_row.wait_for_and_click()
history_export.name_input.wait_for_and_send_keys("my_export.tar.gz")
history_export.export_button.wait_for_and_click()

history_export.running.wait_for_visible()
history_export.running.wait_for_absent(wait_type=gx_selenium_context.wait_types.JOB_COMPLETION)
history_export.success_message.wait_for_visible()

gx_selenium_context.navigate_to_histories_page()
gx_selenium_context.components.histories.import_button.wait_for_and_click()
history_import = gx_selenium_context.components.history_import
history_import.radio_button_remote_files.wait_for_and_click()
files_dialog.ftp_row.wait_for_and_click()
files_dialog.row(uri="gxftp://my_export.tar.gz").wait_for_and_click()

history_import.import_button.wait_for_and_click()

history_import.running.wait_for_visible()
history_import.running.wait_for_absent(wait_type=gx_selenium_context.wait_types.JOB_COMPLETION)
history_import.success_message.wait_for_visible()

gx_selenium_context.navigate_to_histories_page()
newest_history_name = gx_selenium_context.histories_get_history_names()[0]
assert newest_history_name.startswith("imported from archive")