-
Notifications
You must be signed in to change notification settings - Fork 20
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
Draft: replace nosetests with pytest #936
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,18 @@ | |
""" | ||
""" | ||
|
||
from ...util import base_url | ||
from ..functional_tests import FunctionalTest | ||
from ..util import base_url | ||
from ..functional.functional_tests import FunctionalTest | ||
import os.path | ||
|
||
class TestViewerLoading(FunctionalTest): | ||
""" | ||
Test whether the viewer loading functions work | ||
""" | ||
@classmethod | ||
def setUpClass(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The spelling of setup/teardown stuff changes across the board |
||
def setup_class(self): | ||
print("== Running {} ==".format(os.path.basename(__file__))) | ||
super().setUpClass() | ||
super().setup_class() | ||
|
||
def test_viewer_loading_time(self): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,30 +3,26 @@ | |
"""Carry out functional tests on OneZoom pages using an automated browser via selenium | ||
|
||
Example: carry out all tests | ||
nosetests -w ./ tests/functional | ||
python -m pytest ./ tests/functional | ||
Example: carry out all tests for unsponsorable sites (museum displays) | ||
nosetests -vs functional/sponsorship/test_unsponsorable_site.py | ||
python -m pytest -s functional/sponsorship/test_unsponsorable_site.py | ||
Example: carry out test that unsponsorable sites give the correct page for invalid otts | ||
nosetests -vs functional/sponsorship/test_unsponsorable_site.py:TestUnsponsorableSite.test_invalid | ||
|
||
If you have installed the 'rednose' package (pip3 install rednose), you can get nicer output by e.g. | ||
|
||
nosetests -vs ./tests/functional --rednose | ||
python -m pytest -s functional/sponsorship/test_unsponsorable_site.py:TestUnsponsorableSite.test_invalid | ||
|
||
To carry out tests on a remote machine, you can specify a [url][server] and [url][port] | ||
in a config file, which will not give the FunctionalTest class an is_local attribute | ||
and hence will skip tests marked @attr('is_local'). E.g. for testing beta.onezoom.org, you can do | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll want to choose a solution for running the functional tests on beta.onezoom.org, though it doesn't have to look like this |
||
TODO: this is not yet implemented for the functional tests | ||
in nosetests we used to do... | ||
nosetests -vs ./tests/functional --rednose --tc-file beta_cfg.ini | ||
|
||
""" | ||
|
||
import sys | ||
import json | ||
import os | ||
import re | ||
from datetime import datetime | ||
from nose import tools | ||
import requests | ||
import subprocess | ||
import logging | ||
|
@@ -52,7 +48,7 @@ class FunctionalTest(object): | |
is_local = Web2py_server.is_local() | ||
|
||
@classmethod | ||
def setUpClass(self): | ||
def setup_class(self): | ||
def striptext_in_file(line, file): | ||
""" | ||
look for the line as a starting line in the file, stripping whitespace | ||
|
@@ -97,55 +93,50 @@ def striptext_in_file(line, file): | |
selenium_logger.setLevel(logging.WARNING) | ||
#chrome_options = webdriver.ChromeOptions() | ||
#chrome_options.add_experimental_option("mobileEmulation", { "deviceName": "iPhone 7" }) | ||
self.caps = webdriver.ChromeOptions().to_capabilities() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also updated to selenium 4 whilst we're here, so lots of 'find_element_by...' stuff has changed to the new interface |
||
chrome_options = webdriver.ChromeOptions() | ||
# enable browser logging | ||
self.caps['loggingPrefs'] = { 'browser':'ALL' } | ||
self.browser = webdriver.Chrome(desired_capabilities = self.caps) | ||
chrome_options.set_capability('goog:loggingPrefs', { 'browser':'ALL' }) | ||
self.browser = webdriver.Chrome(options=chrome_options) | ||
self.browser.implicitly_wait(1) | ||
|
||
@classmethod | ||
def tearDownClass(self): | ||
def teardown_class(self): | ||
#should test here that we don't have any console.log errors (although we might have logs). | ||
self.browser.quit() | ||
self.web2py.stop_server() | ||
|
||
def setup(self): | ||
def setup_method(self): | ||
""" | ||
By default, clear logs before each test | ||
""" | ||
self.clear_log() | ||
|
||
def teardown(self): | ||
def teardown_method(self): | ||
""" | ||
By default, check javascript errors after each test. If you don't want to do this, e.g. for iframes, thic can be overridden | ||
""" | ||
self.clear_log(check_errors=True) | ||
|
||
@tools.nottest | ||
def element_by_tag_name_exists(self, tag_name): | ||
try: self.browser.find_element_by_tag_name(tag_name) | ||
try: self.browser.find_element(By.TAG_NAME, tag_name) | ||
except NoSuchElementException: return False | ||
return True | ||
|
||
@tools.nottest | ||
def element_by_id_exists(self, id): | ||
try: self.browser.find_element_by_id(id) | ||
try: self.browser.find_element(By.ID, id) | ||
except NoSuchElementException: return False | ||
return True | ||
|
||
@tools.nottest | ||
def element_by_class_exists(self, cls): | ||
try: self.browser.find_element_by_class_name(cls) | ||
try: self.browser.find_element(By.CLASS_NAME, cls) | ||
except NoSuchElementException: return False | ||
return True | ||
|
||
@tools.nottest | ||
def element_by_css_selector_exists(self, css): | ||
try: self.browser.find_element_by_css_selector(css) | ||
try: self.browser.find_element(By.CSS_SELECTOR, css) | ||
except NoSuchElementException: return False | ||
return True | ||
|
||
@tools.nottest | ||
def clear_log(self, check_errors=False): | ||
log = self.browser.get_log('browser') | ||
if check_errors: | ||
|
@@ -155,7 +146,6 @@ def clear_log(self, check_errors=False): | |
if not (message['message'].startswith("https://media.eol.org/content") and "404 (Not Found)" in message['message']): | ||
assert False, "Javascript issue of level {}, : {}".format(message['level'], message['message']) | ||
|
||
@tools.nottest | ||
def zoom_disabled(self): | ||
""" | ||
Check that the touch zoom functionality is disabled. | ||
|
@@ -209,17 +199,17 @@ def has_linkouts(browser, include_site_internal): | |
Depending on the param passed in, we may want to allow internal (relative) links such as | ||
<a href='/sponsored'></a> | ||
""" | ||
for tag in browser.find_elements_by_css_selector("[href^='http']"): | ||
for tag in browser.find_elements(By.CSS_SELECTOR, "[href^='http']"): | ||
if tag.tag_name != u'link' and not tag.get_attribute('href').startswith('http://127.0.0.1'): #should allow e.g. <link href="styles.css"> and http://127.0.0.1:.. | ||
return True | ||
for tag in browser.find_elements_by_css_selector("[href^='//']"): | ||
for tag in browser.find_elements(By.CSS_SELECTOR, "[href^='//']"): | ||
if tag.tag_name != u'link': #should allow e.g. <link href="styles.css"> | ||
return True | ||
|
||
#all hrefs should now be http or https refs to local stuff. We should double check this | ||
#by looking at the tag.attribute which is fully expanded by selenium/chrome to include http | ||
#but we should exclude all page-local links (i.e. beginning with #) | ||
for tag in browser.find_elements_by_css_selector('[href]:not([href^="#"])'): | ||
for tag in browser.find_elements(By.CSS_SELECTOR, '[href]:not([href^="#"])'): | ||
if tag.tag_name != u'link': | ||
if include_site_internal: | ||
return True | ||
|
@@ -234,13 +224,13 @@ def has_linkouts(browser, include_site_internal): | |
def web2py_date_accessed(browser): | ||
#assumes that we have injected the access date into a meta element called 'date_accessed' | ||
#using the web2py code {{response.meta.date_accessed = request.now}} | ||
return datetime.strptime(browser.find_element_by_xpath("//meta[@name='date_accessed']").get_attribute("content"), date_format) | ||
return datetime.strptime(browser.find_element(By.XPATH, "//meta[@name='date_accessed']").get_attribute("content"), date_format) | ||
|
||
def web2py_viewname_contains(browser, expected_view): | ||
#Checks if we have injected the view name into a meta element called 'viewfile' | ||
#using the web2py code {{response.meta.viewfile = response.view}} | ||
try: | ||
return expected_view in browser.find_element_by_xpath("//meta[@name='viewfile']").get_attribute("content") | ||
return expected_view in browser.find_element(By.XPATH, "//meta[@name='viewfile']").get_attribute("content") | ||
except NoSuchElementException: | ||
return False | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,6 @@ | |
# -*- coding: utf-8 -*- | ||
import os | ||
import requests | ||
from nose import tools | ||
from time import sleep | ||
|
||
from selenium import webdriver #to fire up a duplicate page | ||
|
||
|
@@ -17,7 +15,7 @@ class SponsorshipTest(FunctionalTest): | |
""" | ||
|
||
@classmethod | ||
def setUpClass(self): | ||
def setup_class(self): | ||
""" | ||
When setting up the sponsorship pages testing suite we have to create a new appconfig.ini file | ||
and point out web2py instance at it so that we can adjust maintenance_mins and allow_sponsorship | ||
|
@@ -33,7 +31,7 @@ def setUpClass(self): | |
if line.lstrip().startswith("[sponsorship]"): | ||
test.write("maintenance_mins = {}\n".format(self.maintenance_mins)) | ||
test.write("allow_sponsorship = {}\n".format(self.allow_sponsorship)) | ||
super().setUpClass() | ||
super().setup_class() | ||
|
||
#Now get s, from the "normal" OZ viewer, from a museum display, | ||
#from a partner view and also a test case where all links are banned | ||
|
@@ -58,13 +56,12 @@ def setUpClass(self): | |
} | ||
|
||
@classmethod | ||
def tearDownClass(self): | ||
super().tearDownClass() | ||
def teardown_class(self): | ||
super().teardown_class() | ||
print(">> removing temporary appconfig") | ||
os.remove(self.appconfig_loc) | ||
|
||
@tools.nottest | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. renamed some functions so that things we actually want collected as tests start in 'test_' and those that we don't want collected as tests do not |
||
def test_ott(self, extra_assert_tests, ott, extra_assert_tests_from_another_browser=None, browser=None): | ||
def check_ott(self, extra_assert_tests, ott, extra_assert_tests_from_another_browser=None, browser=None): | ||
""" | ||
Test the 4 separate urls, each viewing the same page linked from a different place | ||
(e.g. from the OZ tree viewer versus the min website, vs a museum display) | ||
|
@@ -85,7 +82,7 @@ def test_ott(self, extra_assert_tests, ott, extra_assert_tests_from_another_brow | |
#still forwards to the same page | ||
print(" ... also testing same pages from an alternative browser ...", end="", flush=True) | ||
alt_browser = webdriver.Chrome() | ||
self.test_ott(extra_assert_tests_from_another_browser, ott, None, alt_browser) | ||
self.check_ott(extra_assert_tests_from_another_browser, ott, None, alt_browser) | ||
alt_browser.quit() | ||
#check all the alternative representations too | ||
print("|w2p", end="", flush=True) | ||
|
@@ -107,29 +104,7 @@ def test_ott(self, extra_assert_tests, ott, extra_assert_tests_from_another_brow | |
assert has_linkouts(browser, include_site_internal=True) == False | ||
assert self.zoom_disabled() | ||
print(" ", end="", flush=True) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure what this unused function was about. Looks like just an unfinished idea for a test? |
||
@tools.nottest | ||
def test_md_sandbox(self, ott): | ||
""" | ||
Follow any links from the museum display page and collect a list. If any are external, return False | ||
""" | ||
self.browser.get(self.urls['treeviewer_md'](ott)) | ||
#Although any element can potentially link out to another page using javascript, | ||
# the most likely elements that will cause a sandbox escape on our own page | ||
# are <a href=...> <form action=...> <area href=...>, or <button onclick=...> | ||
# For external pages (e.g. wikipages) we shoud ensure that JS is stripped. | ||
def first_external_link(self, already_followed): | ||
""" | ||
Recurse through possible links from this page until we find an external one | ||
in which case we can return False, or | ||
""" | ||
return | ||
|
||
for elem in self.browser.find_elements_by_tag_name('a'): | ||
href = elem.get_attribute('href') | ||
|
||
|
||
@tools.nottest | ||
def never_looked_at_ottname(self): | ||
""" | ||
Find an unpopular species that has never been looked at (i.e. does not have an entry in the reservations table | ||
|
@@ -151,7 +126,6 @@ def never_looked_at_ottname(self): | |
db_cursor.close() | ||
return ott, sciname | ||
|
||
@tools.nottest | ||
def delete_reservation_entry(self, ott, name, email=test_email): | ||
""" | ||
Warning: this will REMOVE data. Make sure that this is definitely one of the previously not looked at species | ||
|
@@ -170,30 +144,26 @@ def delete_reservation_entry(self, ott, name, email=test_email): | |
db_cursor.close() | ||
return n_rows | ||
|
||
@tools.nottest | ||
def invalid_ott(self): | ||
""" | ||
Give an invalid OTT. We should also test for 'species' with no space in the name, but we can't be guaranteed | ||
that there will be any of these | ||
""" | ||
return -1 | ||
|
||
@tools.nottest | ||
def banned_unsponsored_ott(self): | ||
""" | ||
Human ott is always banned, never sponsored | ||
""" | ||
return self.humanOTT | ||
|
||
@tools.nottest | ||
def banned_sponsored_ott(self): | ||
""" | ||
We could possibly pick pandas here, but we are not assured that they will be sponsored on all sites | ||
""" | ||
raise NotImplementedError | ||
|
||
|
||
@tools.nottest | ||
def sponsored_ott(self): | ||
""" | ||
We might also want to test a sponsored banned species here, like the giant panda | ||
|
@@ -206,7 +176,6 @@ def sponsored_ott(self): | |
else: | ||
return sponsored[0]['OTT_ID'] | ||
|
||
@tools.nottest | ||
def visit_data(self, ott): | ||
""" | ||
Return the num_views, last_view and the reserve_time for this ott | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was redirecting to a non-existent page