Skip to content
Open
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
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion controllers/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ def licence():
return dict()

def news():
redirect(URL('default', 'milestones.html'))
Copy link
Collaborator Author

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

redirect(URL('default', 'timeline.html'))
return dict()


Expand Down
10 changes: 6 additions & 4 deletions models/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os.path
import img
import json
import os

#########################################################################
## This scaffolding model makes your app work on Google App Engine too
Expand All @@ -24,17 +25,18 @@
## this will also set migration=False for all tables, so that the DB table definitions are fixed
is_testing = True

custom_appconfig_path = os.environ.get('ONEZOOM_APPCONFIG')

## Read configuration
if (
is_testing and
request.env.cmd_options is not None and
len(request.env.cmd_options.args) > 1 and
os.path.isfile(request.env.cmd_options.args[-1])
custom_appconfig_path and
os.path.isfile(custom_appconfig_path)
):
# For unit testing, we might want to load a different appconfig.ini file, which can
# be passed in to the rocket server as the last arg on the command-line (on the main
# server, `request.env.cmd_options` is undefined, and we default back to appconfig.ini)
myconf = AppConfig(request.env.cmd_options.args[-1], reload=is_testing)
myconf = AppConfig(custom_appconfig_path, reload=is_testing)
else:
# Reload config on each request when is_testing (i.e. not production)
myconf = AppConfig(reload=is_testing)
Expand Down
2 changes: 1 addition & 1 deletion tests/benchmarking/API/test_textsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
8 changes: 4 additions & 4 deletions tests/benchmarking/test_viewer_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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):
"""
Expand Down
58 changes: 24 additions & 34 deletions tests/functional/functional_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. We should record this in a README somewhere.

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
Expand All @@ -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
Expand All @@ -69,7 +65,7 @@ def striptext_in_file(line, file):


try:
self.web2py = Web2py_server(self.appconfig_loc)
self.web2py = Web2py_server(self.test_appconfig_loc)
except AttributeError:
self.web2py = Web2py_server()

Expand Down Expand Up @@ -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()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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:
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -278,7 +268,7 @@ def make_temp_minlife_file(self):
f.write(response.content)
self.temp_minlife_created += [minlife_file_location.format(i)]
#process links (see the partial_install command in Gruntfile.js in the app dir)
subprocess.call(['perl', '-i', os.path.join(web2py_app_dir, 'OZprivate','ServerScripts','Utilities','partial_install.pl'), minlife_file_location.format(i)])
subprocess.call([sys.executable, os.path.join(web2py_app_dir, 'OZprivate','ServerScripts','Utilities','partial_install.py'), minlife_file_location.format(i)])
return minlife_file_location.format(i)
else:
raise Exception("There are already many test files in {}. Please remove some before continuing".format(minlife_file_location))
Expand Down
Loading