Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
8477faeb
Commit
8477faeb
authored
Dec 03, 2019
by
Carsten Rose
Browse files
Merge branch 'selenium_marcel' into 'master'
Selenium marcel See merge request
!218
parents
8a64f2fb
44a67188
Pipeline
#2849
passed with stages
in 3 minutes and 26 seconds
Changes
8
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
docker/README.md
View file @
8477faeb
...
...
@@ -20,6 +20,9 @@ For the below scripts to work please name the images ```python-selenium``` and `
## Run qfq in docker container from scratch
1. clone qfq git project
```git clone https://git.math.uzh.ch/typo3/qfq```
2. change to project directory (qfq)
3. ```make bootstrap```
4. ``` cd docker```
...
...
@@ -53,6 +56,7 @@ Assumes you have run qfq in docker as explained above.
Assumes you have run qfq in docker as explained above.
0. Install selenium for python: ```
python3 -m pip install --user selenium
```
1. again from the docker directory run ```
./run_selenium_tests_local.sh
```
## Run a single selenium test file on local machine
...
...
@@ -88,4 +92,4 @@ Assumes you have run qfq in docker as explained above.
```
unzip /tmp/chromedriver.zip chromedriver
```
3. export chromedriver path environment variable before running selenium tests locally
```
export CHROMEDRIVER_PATH=
<absolute
path
to
chromedriver
>
/chromedriver
```
\ No newline at end of file
```
export CHROMEDRIVER_PATH=
<absolute
path
to
chromedriver
>
/chromedriver
```
docker/db_fixture_qfq.sql
View file @
8477faeb
This diff is collapsed.
Click to expand it.
docker/db_fixture_t3.sql
View file @
8477faeb
This diff is collapsed.
Click to expand it.
docker/dump_databases.sh
View file @
8477faeb
#!/bin/bash -ex
source
run_qfq_docker.output
MYSQL_ROOT_PASSWORD
=
crazyfish123
MYSQL_ROOT_PASSWORD
=
MN7HKEB7AnvdVKQE
# qfq database dump
mysqldump
-u
root
--password
=
${
MYSQL_ROOT_PASSWORD
}
--port
=
${
DB_PORT
}
-h
127.0.0.1 qfq_db
>
db_fixture_qfq.sql
...
...
docker/run_qfq_docker.sh
View file @
8477faeb
...
...
@@ -73,7 +73,7 @@ until mysql -u root --password=${MYSQL_ROOT_PASSWORD} --port=${DB_PORT} -h 127.0
-e
"CREATE DATABASE
${
T3_DATABASE
}
; CREATE DATABASE
${
QFQ_DATABASE
}
"
do
tries
=
$((
tries+1
))
if
[[
"
${
tries
}
"
-gt
3
0
]]
;
then
if
[[
"
${
tries
}
"
-gt
6
0
]]
;
then
echo
"Timeout: could not connect to database."
exit
1
;
fi
...
...
docker/run_selenium_tests_local.sh
View file @
8477faeb
#!/bin/bash
-ex
#!/bin/bash
source
run_qfq_docker.output
# download chromedriver
if
[
!
-f
chromedriver
]
;
then
wget
-O
/tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/
`
curl
-sS
chromedriver.storage.googleapis.com/LATEST_RELEASE
`
/chromedriver_linux64.zip
unzip /tmp/chromedriver.zip chromedriver
chmod
+x chromedriver
# this function prints a separator
function
print_separator
{
# prints the separator
echo
-e
"----------------------------------------------------------------------"
}
# prints the starting separator
print_separator
# checks that a file named geckodriver doesn't already exist
if
[
!
-f
"geckodriver"
]
;
then
# stores the current version of the driver
gecko_version
=
$(
curl
--silent
"https://api.github.com/repos/mozilla/geckodriver/releases/latest"
|
grep
-Po
'"tag_name": "\K.*?(?=")'
)
&> /dev/null
# downloads the geckodriver from github
wget
-O
/tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/
${
gecko_version
}
/geckodriver-
${
gecko_version
}
-linux64
.tar.gz &> /dev/null
# unzips the downloaded geckodriver
tar
xzf /tmp/geckodriver.tar.gz geckodriver &> /dev/null
# makes the geckodriver executable
chmod
+x geckodriver &> /dev/null
# prints a success output
echo
-e
"Successfully downloaded geckodriver"
fi
# checks that a file named chromedriver doesn't already exist
if
[
!
-f
"chromedriver"
]
;
then
# downloads the newest version of the chromedriver from google
wget
-O
/tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/
`
curl
-sS
chromedriver.storage.googleapis.com/LATEST_RELEASE
`
/chromedriver_linux64.zip &> /dev/null
# unzips the downloaded chromedriver
unzip /tmp/chromedriver.zip chromedriver &> /dev/null
# makes the chromedriver executable
chmod
+x chromedriver &> /dev/null
# prints a success output
echo
-e
"Successfully downloaded chromedriver"
fi
# reads the url to test from the input variable
SELENIUM_URL
=
$1
# checks if the selenium url is not given
if
[
-z
$SELENIUM_URL
]
;
then
SELENIUM_URL
=
"http://127.0.0.1:
${
T3_PORT
}
"
fi
# defines the url to be used during testing
export
SELENIUM_URL
=
$SELENIUM_URL
# stores the default engine
DEFAULT_ENGINE
=
"chrome"
# reads the engine from the 2nd input variable
ENGINE
=
$2
# checks if an engine is not specified
if
[
-z
$ENGINE
]
;
then
# defines the default engine to use during tests
export
BROWSER
=
$DEFAULT_ENGINE
# defines the path to the drivers of the engine
export
DRIVER_PATH
=
"
${
PWD
}
/
${
DEFAULT_ENGINE
}
driver"
else
# defines the engine to use during tests
export
BROWSER
=
$ENGINE
# defines the path to the drivers of the engine
export
DRIVER_PATH
=
"
${
PWD
}
/
${
ENGINE
}
driver"
fi
# stores the default headless option
DEFAULT_HEADLESS
=
"no"
# reads the headless option from the 3rd input variable
HEADLESS
=
$3
# checks if the headless parameter is not specified
if
[
-z
$HEADLESS
]
;
then
# defines if the browser gui should open
export
SELENIUM_HEADLESS
=
$DEFAULT_HEADLESS
else
# defines if the browser gui should open
export
SELENIUM_HEADLESS
=
$HEADLESS
fi
# stores the default slowdown
DEFAULT_SLOWDOWN
=
"0"
# reads the slowdown from the 4th input variable
SLOWDOWN
=
$4
# checks if the slowdown parameter is not specified
if
[
-z
$SLOWDOWN
]
;
then
# defines what slowdown should be applied
export
SELENIUM_SLOWDOWN
=
$DEFAULT_SLOWDOWN
else
# defines what slowdown should be applied
export
SELENIUM_SLOWDOWN
=
$SLOWDOWN
fi
export
CHROMEDRIVER_PATH
=
"
${
PWD
}
/chromedriver"
# run tests
cd
../extension/Tests/selenium
export
SELENIUM_URL
=
"http://127.0.0.1:
${
T3_PORT
}
"
export
SELENIUM_HEADLESS
=
"no"
python
-m
unittest discover
\ No newline at end of file
# prints running tests
echo
-e
-n
"Running tests: "
# runs the python tests
python3
-W
ignore
-m
unittest discover
# checks if the tests were successful
if
[
$?
-eq
0
]
;
then
print_separator
# prints a success message
echo
-e
"Successfully tested
${
SELENIUM_URL
}
"
else
print_separator
# prints a success message
echo
-e
"Failed while testing
${
SELENIUM_URL
}
"
fi
# prints the trailing separator
print_separator
# exits the program
exit
0
extension/Tests/selenium/qfqselenium.py
View file @
8477faeb
# -*- coding: utf-8 -*-
from
selenium
import
webdriver
from
selenium.webdriver.chrome.options
import
Options
from
selenium.webdriver.firefox.options
import
Options
as
FFOptions
from
selenium.webdriver.support.ui
import
Select
from
selenium.common.exceptions
import
StaleElementReferenceException
,
NoSuchElementException
,
WebDriverException
from
selenium.webdriver.support.ui
import
WebDriverWait
from
selenium.webdriver.common.by
import
By
from
selenium.webdriver.support
import
expected_conditions
as
EC
from
selenium.common.exceptions
import
TimeoutException
import
unittest
import
os
import
sys
import
glob
import
time
import
codecs
import
re
import
socket
import
random
import
string
def
urlJoin
(
url_list
):
return
'/'
.
join
(
s
.
strip
(
'/'
)
for
s
in
url_list
)
def
urlFromHostname
(
hostname
,
port
=
80
):
try
:
return
'http://'
+
socket
.
gethostbyname
(
hostname
)
+
':'
+
str
(
port
)
except
socket
.
gaierror
as
e
:
return
'unknown'
"""
this function returns a url from a given hostname and a given port
"""
try
:
return
'http://'
+
socket
.
gethostbyname
(
hostname
)
+
':'
+
str
(
port
)
except
socket
.
gaierror
as
e
:
return
'unknown'
class
QfqSeleniumTestCase
(
unittest
.
TestCase
):
"""initialize selenium and add custom commands and asserts"""
"""
this class initializes selenium and adds custom commands and asserts.
"""
max_number_of_log_files_to_keep
=
100
gecko_browser_name
=
"gecko"
gecko_driver_path
=
"geckodriver"
chrome_browser_name
=
"chrome"
chrome_driver_path
=
"chromedriver"
# These variables can be overwritten by environment variables of the same name
CHROMEDRIVER_PATH
=
"chromedriver"
# these variables can be overwritten by environment variables of the same name
BROWSER
=
chrome_browser_name
DRIVER_PATH
=
""
if
BROWSER
==
chrome_browser_name
:
DRIVER_PATH
=
chrome_driver_path
elif
BROWSER
==
gecko_browser_name
:
DRIVER_PATH
=
gecko_driver_path
SELENIUM_LOGS_PATH
=
os
.
getcwd
()
SELENIUM_HEADLESS
=
'yes'
# set environment variable to 'no' to turn off
SELENIUM_HEADLESS
=
'yes'
# set environment variable to 'no' to turn off
SELENIUM_URL
=
urlFromHostname
(
'typo3container'
)
SELENIUM_SLOWDOWN
=
0
@
classmethod
def
setUpClass
(
cls
):
"""executed by unittest once before any tests are executed"""
"""
executed by unittest once before any tests are executed.
"""
# read environment variables
cls
.
CHROMEDRIVER_PATH
=
os
.
environ
.
get
(
'CHROMEDRIVER_PATH'
,
cls
.
CHROMEDRIVER_PATH
)
# reads the environment variables
cls
.
BROWSER
=
os
.
environ
.
get
(
'BROWSER'
,
cls
.
BROWSER
)
cls
.
DRIVER_PATH
=
os
.
environ
.
get
(
'DRIVER_PATH'
,
cls
.
DRIVER_PATH
)
cls
.
SELENIUM_LOGS_PATH
=
os
.
environ
.
get
(
'SELENIUM_LOGS_PATH'
,
cls
.
SELENIUM_LOGS_PATH
)
cls
.
SELENIUM_HEADLESS
=
os
.
environ
.
get
(
'SELENIUM_HEADLESS'
,
cls
.
SELENIUM_HEADLESS
)
cls
.
SELENIUM_URL
=
os
.
environ
.
get
(
'SELENIUM_URL'
,
cls
.
SELENIUM_URL
)
cls
.
SELENIUM_SLOWDOWN
=
float
(
os
.
environ
.
get
(
'SELENIUM_SLOWDOWN'
,
cls
.
SELENIUM_SLOWDOWN
))
# setup log directory, delete very old log files
cls
.
selenium_logs_dir
=
'selenium_logs'
...
...
@@ -52,42 +79,58 @@ class QfqSeleniumTestCase(unittest.TestCase):
log_file_pattern
=
re
.
compile
(
'[0-9]{8}-{1}[0-9]{6}.*'
)
for
filename
in
log_files_to_delete
:
if
not
log_file_pattern
.
match
(
filename
):
print
'non log file in log directory found: '
,
filename
print
(
'non log file in log directory found: '
,
filename
)
continue
file_path
=
os
.
path
.
join
(
cls
.
selenium_logs_dir_path
,
filename
)
os
.
remove
(
file_path
)
# initialize webdriver
chrome_options
=
Options
()
if
cls
.
SELENIUM_HEADLESS
!=
'no'
:
chrome_options
.
add_argument
(
"--headless"
)
chrome_options
.
add_argument
(
"--window-size=1920,1080"
)
chrome_options
.
add_argument
(
"--disable-dev-shm-usage"
)
chrome_options
.
add_argument
(
"--no-sandbox"
)
desired_capabilities
=
{
'UNEXPECTED_ALERT_BEHAVIOUR'
:
'ignore'
}
cls
.
driver
=
webdriver
.
Chrome
(
chrome_options
=
chrome_options
,
executable_path
=
cls
.
CHROMEDRIVER_PATH
,
desired_capabilities
=
desired_capabilities
)
# initializes webdriver
if
cls
.
BROWSER
==
cls
.
chrome_browser_name
:
chrome_options
=
Options
()
if
cls
.
SELENIUM_HEADLESS
!=
'no'
:
chrome_options
.
add_argument
(
"--headless"
)
chrome_options
.
add_argument
(
"--window-size=1920,1080"
)
chrome_options
.
add_argument
(
"--disable-dev-shm-usage"
)
chrome_options
.
add_argument
(
"--no-sandbox"
)
desired_capabilities
=
{
'UNEXPECTED_ALERT_BEHAVIOUR'
:
'ignore'
}
cls
.
driver
=
webdriver
.
Chrome
(
chrome_options
=
chrome_options
,
executable_path
=
cls
.
DRIVER_PATH
,
desired_capabilities
=
desired_capabilities
)
elif
cls
.
BROWSER
==
cls
.
gecko_browser_name
:
firefox_options
=
FFOptions
()
if
cls
.
SELENIUM_HEADLESS
!=
'no'
:
firefox_options
.
headless
=
True
desired_capabilities
=
webdriver
.
DesiredCapabilities
().
FIREFOX
cls
.
driver
=
webdriver
.
Firefox
(
firefox_options
=
firefox_options
,
executable_path
=
cls
.
DRIVER_PATH
,
capabilities
=
desired_capabilities
)
cls
.
driver
.
set_window_size
(
1920
,
1080
)
cls
.
driver
.
implicitly_wait
(
30
)
@
classmethod
def
tearDownClass
(
cls
):
"""executed by unittest after all test cases were executed"""
"""
executed by unittest after all test cases were executed
"""
cls
.
driver
.
quit
()
def
tearDown
(
self
):
"""executed by unittest after every single test case"""
"""
executed by unittest after every single test case
"""
# save website state on failure
if
sys
.
exc_info
()[
0
]:
filename
=
time
.
strftime
(
"%Y%m%d-%H%M%S"
)
+
'_'
+
self
.
_testMethodName
screenshot_file_path
=
self
.
qfq_save_screenshot
(
filename
)
html_file_path
=
self
.
qfq_save_html
(
filename
)
print
'Test failed.'
print
'Webpage screenshot saved to '
+
screenshot_file_path
print
'Webpage Html saved to '
+
html_file_path
print
'!!! ATTENTION !!!: If you get the error "unexpected alert open",'
\
+
'there must be another error above which actually triggers the test failure.'
print
(
'Test failed.'
)
print
(
'Webpage screenshot saved to '
+
screenshot_file_path
)
print
(
'Webpage Html saved to '
+
html_file_path
)
print
(
'!!! ATTENTION !!!: If you get the error "unexpected alert open",'
\
+
'there must be another error above which actually triggers the test failure.'
)
def
_prepare_log_file_path
(
self
,
filename
,
suffix
=
''
):
file_path
=
os
.
path
.
join
(
self
.
selenium_logs_dir_path
,
filename
+
suffix
)
...
...
@@ -101,49 +144,300 @@ class QfqSeleniumTestCase(unittest.TestCase):
except
(
StaleElementReferenceException
,
NoSuchElementException
,
WebDriverException
):
retries
-=
1
def
_slow_available
(
func
):
"""
adds a globally specified slowdown to a function
"""
def
f
(
*
args
,
**
kwargs
):
self
=
args
[
0
]
self
.
qfq_wait
(
self
.
SELENIUM_SLOWDOWN
)
func
(
*
args
,
**
kwargs
)
return
f
# ----- DATA SAVING ----- #
def
qfq_save_screenshot
(
self
,
filename
):
"""
saves a screenshot of the page to a logfile with a given name
"""
screenshot_file_path
=
self
.
_prepare_log_file_path
(
filename
,
'.png'
)
self
.
driver
.
save_screenshot
(
screenshot_file_path
)
return
screenshot_file_path
def
qfq_save_html
(
self
,
filename
):
"""
saves the html source to a logfile with a given name
"""
html_file_path
=
self
.
_prepare_log_file_path
(
filename
,
'.html'
)
with
codecs
.
open
(
html_file_path
,
"w"
,
"utf-8"
)
as
f
:
f
.
write
(
self
.
driver
.
page_source
)
return
html_file_path
def
qfq_goto
(
self
,
web_path
):
url
=
urlJoin
([
self
.
SELENIUM_URL
,
web_path
])
self
.
driver
.
get
(
url
)
def
qfq_wait
(
self
,
seconds
):
time
.
sleep
(
seconds
)
# ----- ASSERTIONS ----- #
def
qfq_assert_text_exists
(
self
,
text
):
self
.
assertTrue
(
text
in
self
.
driver
.
page_source
)
"""
asserts if a given text exists on the webpage
"""
self
.
assertTrue
(
str
(
text
)
in
self
.
driver
.
page_source
)
def
qfq_assert_text_absent
(
self
,
text
):
self
.
assertTrue
(
text
not
in
self
.
driver
.
page_source
)
"""
asserts if a given text is absent on the webpage
"""
self
.
assertTrue
(
str
(
text
)
not
in
self
.
driver
.
page_source
)
def
qfq_assert_true
(
self
,
bool
):
"""
asserts if a given bool is true
"""
self
.
assertTrue
(
bool
)
def
qfq_assert_false
(
self
,
bool
):
"""
asserts if a given bool is false
"""
self
.
assertFalse
(
bool
)
# ----- SELECTORS ----- #
def
qfq_get_element_by_css_selector
(
self
,
selector
,
select_invisibles
=
True
):
"""
this funtion returns the first element to match a given css selector
"""
element
=
WebDriverWait
(
self
.
driver
,
1
).
until
(
EC
.
presence_of_element_located
((
By
.
CSS_SELECTOR
,
selector
)))
if
self
.
qfq_element_is_visible
(
element
)
or
select_invisibles
:
return
element
else
:
raise
ValueError
(
"The element with the given selector is not visible on screen"
)
def
qfq_find_by_data_ref
(
self
,
data_reference
):
return
self
.
driver
.
find_element_by_css_selector
(
"[data-reference='{}']"
.
format
(
data_reference
))
def
qfq_get_element_by_id
(
self
,
id
,
select_invisibles
=
True
):
"""
returns an element which is identified by a given id
"""
id_occurences
=
self
.
driver
.
page_source
.
count
(
" id=
\"
"
+
id
+
"
\"
"
)
if
id_occurences
==
0
or
id_occurences
>
1
:
raise
ValueError
(
"No element could be identified with the given id. The page source contains more than one or no element with the given id."
)
return
self
.
qfq_get_element_by_css_selector
(
"#"
+
str
(
id
),
select_invisibles
)
def
qfq_get_element_by_data_ref
(
self
,
data_reference
,
select_invisibles
=
True
):
"""
returns an element which is identified by a given data reference.
If there is no such data reference it throws an exception.
"""
return
self
.
qfq_get_element_by_css_selector
(
"[data-reference='"
+
data_reference
+
"']"
,
select_invisibles
)
def
qfq_get_element_by_xpath
(
self
,
xpath
,
select_invisibles
=
True
):
"""
this function returns an element identified by a given xpath
"""
element
=
WebDriverWait
(
self
.
driver
,
1
).
until
(
EC
.
presence_of_element_located
((
By
.
XPATH
,
xpath
)))
if
self
.
qfq_element_is_visible
(
element
)
or
select_invisibles
:
return
element
else
:
raise
ValueError
(
"The element with the given selector is not visible on screen"
)
# ----- ACTIONS ----- #
@
_slow_available
def
qfq_goto_page
(
self
,
web_path
):
"""
goes to a sub page of the given path
"""
url
=
urlJoin
([
self
.
SELENIUM_URL
,
str
(
web_path
)])
self
.
driver
.
get
(
url
)
@
_slow_available
def
qfq_fill_textfield
(
self
,
data_reference
,
text
):
self
.
qfq_find_by_data_ref
(
data_reference
).
send_keys
(
text
)
"""
fills a given string into a text field which
is identified by the given data reference
"""
self
.
qfq_get_element_by_data_ref
(
data_reference
).
send_keys
(
str
(
text
))
@
_slow_available
def
qfq_clear_textfield
(
self
,
data_reference
):
"""
clears a textfield with a given data reference
"""
self
.
qfq_get_element_by_data_ref
(
data_reference
).
clear
()
@
_slow_available
def
qfq_dropdown_select
(
self
,
data_reference
,
option
):
Select
(
self
.
qfq_find_by_data_ref
(
data_reference
)).
select_by_visible_text
(
option
)
"""
selects an option (with the option's text)
from a dropdown list by data reference
"""
Select
(
self
.
qfq_get_element_by_data_ref
(
data_reference
)
).
select_by_visible_text
(
str
(
option
))
@
_slow_available
def
qfq_radio_select
(
self
,
text
):
"""
selects a radio button in a radio button set
"""
self
.
qfq_click_element_with_xpath
(
"//label[text()='"
+
str
(
text
)
+
"']"
)
@
_slow_available
def
qfq_checkbox_select
(
self
,
text
):
"""
selects a checkbox in a checkbox set
"""
# TODO doesn't work currently because qfq uses div instead of label
# self.qfq_click_element_with_xpath(
# "//label[text()='" + str(text) + "']"
# )
@
_slow_available
def
qfq_open_pill
(
self
,
name
):
"""
this function opens a pill by name
"""
self
.
qfq_click_element_with_xpath
(
"//*[@id='qfqTabs']//a[text()='"
+
str
(
name
)
+
"']"
)
@
_slow_available
def
qfq_upload_file
(
self
,
data_reference
,
file_name
,
suffix
,
size
):
"""
this function uploads a generated file from the given
arguments size and suffix. This file is uploaded to the
input with the given data reference.
"""
# stores the tmp dir name
tmp_dir
=
"tmp"
# checks if the tmp dir doesn't already exist
if
not
os
.
path
.
exists
(
tmp_dir
):
# creates tmp dir if it doesn't exist
os
.
makedirs
(
tmp_dir
)
# loops through all files in the tmp directory
for
f
in
glob
.
glob
(
tmp_dir
+
"/*."
+
suffix
):
# removes each file (old test files)
os
.
remove
(
f
)
# stores the path for the file
file_path
=
os
.
getcwd
()
+
"/"
+
tmp_dir
+
"/"
+
file_name
+
"."
+
suffix
# opens the file from the file path (creates the file)
with
open
(
file_path
,
"w"
)
as
f
:
# writes some random text to the file with the given size
f
.
write
(
self
.
qfq_generate_random_string
(
size
))
# uploads the created file
self
.
qfq_get_element_by_data_ref
(
data_reference
).
send_keys
(
file_path
)
# ----- BUTTONS ----- #
@
_slow_available
def
qfq_click_new_form_button
(
self
):
self
.
qfq_find_by_data_ref
(
'newForm'
).
click
()
"""
clicks the button to create a new form
"""
self
.
qfq_click_element_with_data_ref
(
'newForm'
)
@
_slow_available
def
qfq_click_close_form_button
(
self
):
def
f
():
self
.
driver
.
find_element_by_id
(
'close-button'
).
click
()
"""
clicks the close button when adding a new data entry into a form
"""
def
f
():
self
.
qfq_click_element_with_id
(
'close-button'
)
self
.
_retry_on_certain_exceptions
(
f
)
@
_slow_available
def
qfq_click_save_form_button
(
self
):
self
.
driver
.
find_element_by_id
(
'save-button'
).
click
()
"""
clicks the save button when adding a new data entry into a form
"""
self
.
qfq_click_element_with_id
(
'save-button'
)
@
_slow_available
def
qfq_click_element_with_text
(
self
,
element_tag
,
text
):
"""
clicks a given element name in the dom that contains
the given text
"""
def
f
():
self
.
qfq_get_element_by_xpath
(
"//"
+
element_tag
+
"[text()='"
+
text
+
"']"
).
click
()
self
.
_retry_on_certain_exceptions
(
f
)
@
_slow_available
def
qfq_click_element_with_data_ref
(
self
,
data_reference
):
"""
clicks an element with a given data reference
"""
self
.
qfq_get_element_by_data_ref
(
data_reference
).
click
()
@
_slow_available
def
qfq_click_element_with_id
(
self
,
id
):
"""
clicks a button with a given id
"""
self
.
qfq_get_element_by_id
(
id
).
click
()
@
_slow_available
def
qfq_click_element_with_xpath
(
self
,
xpath
):
"""
clicks an element with a given xpath
"""
def
f
():
self
.
qfq_get_element_by_xpath
(
xpath
).
click
()