From a01594ffd5d340529643d43a7d18a75f4ee0defb Mon Sep 17 00:00:00 2001 From: Jared Khan Date: Sat, 18 Jan 2025 15:43:01 +0000 Subject: [PATCH] Draft: replace nosetests with pytest --- Gruntfile.js | 2 +- controllers/default.py | 2 +- tests/benchmarking/API/test_textsearch.py | 2 +- tests/benchmarking/test_viewer_loading.py | 8 +-- tests/functional/functional_tests.py | 54 ++++++++----------- .../sponsorship/sponsorship_tests.py | 43 +++------------ .../sponsorship/test_maintenance_mode.py | 23 ++++---- .../sponsorship/test_normal_site.py | 41 +++++++------- .../sponsorship/test_unsponsorable_site.py | 14 ++--- tests/functional/test_functions_in_default.py | 18 +++++-- tests/functional/test_webpage_spidering.py | 6 +-- .../functional/treeviewer/test_image_info.py | 44 +++++++-------- .../treeviewer/test_language_localisation.py | 4 +- .../treeviewer/test_links_and_infoboxes.py | 4 +- tests/functional/treeviewer/test_sandbox.py | 4 +- tests/functional/treeviewer/test_tabs.py | 4 +- .../treeviewer/test_tree_data_mismatch.py | 35 ++++++------ .../treeviewer/test_viewer_availability.py | 30 +++++------ .../treeviewer/test_viewer_errors.py | 5 +- .../functional/treeviewer/test_viewer_urls.py | 15 +++--- tests/functional/treeviewer/test_wikipages.py | 4 +- tests/requirements.txt | 5 +- tests/site_setup/test_database_settings.py | 4 +- tests/site_setup/test_image_files.py | 8 +-- tests/unit/test_private_background_tasks.py | 1 + tests/util.py | 19 ++++--- views/default/endorsements.html | 2 +- 27 files changed, 182 insertions(+), 219 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 92be7da9..e626a1d8 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -95,7 +95,7 @@ module.exports = function (grunt) { } }, test_server_functional: { - command: 'nosetests3 tests/functional/' + command: 'pytest tests/functional/' }, test_client: { command: 'npm run test' diff --git a/controllers/default.py b/controllers/default.py index 1d94cdda..3b54e2e8 100755 --- a/controllers/default.py +++ b/controllers/default.py @@ -1807,7 +1807,7 @@ def licence(): return dict() def news(): - redirect(URL('default', 'milestones.html')) + redirect(URL('default', 'timeline.html')) return dict() diff --git a/tests/benchmarking/API/test_textsearch.py b/tests/benchmarking/API/test_textsearch.py index 3cd6dca0..769ec7b9 100755 --- a/tests/benchmarking/API/test_textsearch.py +++ b/tests/benchmarking/API/test_textsearch.py @@ -168,7 +168,7 @@ class TestTextsearch(object): replicates = 3 @classmethod - def setUpClass(self): + def setup_class(self): self.web2py = Web2py_server() wait_for_server_active() colorama.init() diff --git a/tests/benchmarking/test_viewer_loading.py b/tests/benchmarking/test_viewer_loading.py index 1c1bac89..3027da02 100644 --- a/tests/benchmarking/test_viewer_loading.py +++ b/tests/benchmarking/test_viewer_loading.py @@ -2,8 +2,8 @@ """ """ -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): @@ -11,9 +11,9 @@ class TestViewerLoading(FunctionalTest): Test whether the viewer loading functions work """ @classmethod - def setUpClass(self): + def setup_class(self): print("== Running {} ==".format(os.path.basename(__file__))) - super().setUpClass() + super().setup_class() def test_viewer_loading_time(self): """ diff --git a/tests/functional/functional_tests.py b/tests/functional/functional_tests.py index 55f59e27..68cc312e 100755 --- a/tests/functional/functional_tests.py +++ b/tests/functional/functional_tests.py @@ -3,22 +3,19 @@ """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 - + 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 @@ -26,7 +23,6 @@ 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() + 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 """ - 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. 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. 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 diff --git a/tests/functional/sponsorship/sponsorship_tests.py b/tests/functional/sponsorship/sponsorship_tests.py index da7860f7..a6301412 100644 --- a/tests/functional/sponsorship/sponsorship_tests.py +++ b/tests/functional/sponsorship/sponsorship_tests.py @@ -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 - 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) - - @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
, or