Files
python-tdd/src/functional_tests/base.py

108 lines
3.6 KiB
Python

import os
import time
from datetime import datetime
from django.conf import settings
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from pathlib import Path
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from .container_commands import create_session_on_server, reset_database
from .management.commands.create_session import create_pre_authenticated_session
MAX_WAIT = 10
SCREEN_DUMP_LOCATION = Path(__file__).absolute().parent / "screendumps"
# Decorator fns
def wait(fn):
def modified_fn(*args, **kwargs):
start_time = time.time()
while True:
try:
return fn(*args, **kwargs)
except (AssertionError, WebDriverException) as e:
if time.time() - start_time > MAX_WAIT:
raise e
time.sleep(0.5)
return modified_fn
# Functional Tests
class FunctionalTest(StaticLiveServerTestCase):
# Helper methods
def setUp(self):
options = webdriver.FirefoxOptions()
if os.environ.get("HEADLESS"):
options.add_argument("--headless")
self.browser = webdriver.Firefox(options=options)
self.test_server = os.environ.get("TEST_SERVER")
if self.test_server:
self.live_server_url = 'http://' + self.test_server
reset_database(self.test_server)
def tearDown(self):
if self._test_has_failed():
if not SCREEN_DUMP_LOCATION.exists():
SCREEN_DUMP_LOCATION.mkdir(parents=True)
self.take_screenshot()
self.dump_html()
self.browser.quit()
super().tearDown()
def _test_has_failed(self):
return self._outcome.result.failures or self._outcome.result.errors
def take_screenshot(self):
path = SCREEN_DUMP_LOCATION / self._get_filename("png")
print("screendumping to", path)
self.browser.get_screenshot_as_file(str(path))
def dump_html(self):
path = SCREEN_DUMP_LOCATION / self._get_filename("html")
print("dumping page html to", path)
path.write_text(self.browser.page_source)
def _get_filename(self, extension):
timestamp = datetime.now().isoformat().replace(":", ".")
return (
f"{self.__class__.__name__}.{self._testMethodName}-{timestamp}.{extension}"
)
@wait
def wait_for(self, fn):
return fn()
def create_pre_authenticated_session(self, email):
if self.test_server:
session_key = create_session_on_server(self.test_server, email)
else:
session_key = create_pre_authenticated_session(email)
## to set a cookie we need to first visit the domain
## 404 pages load the quickest!
self.browser.get(self.live_server_url + "/404_no_such_url/")
self.browser.add_cookie(
dict(
name=settings.SESSION_COOKIE_NAME,
value=session_key,
path="/",
)
)
@wait
def wait_to_be_logged_in(self, email):
self.browser.find_element(By.CSS_SELECTOR, "#id_logout"),
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
self.assertIn(email, navbar.text)
@wait
def wait_to_be_logged_out(self, email):
lambda: self.browser.find_element(By.CSS_SELECTOR, "input[name=email]"),
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
self.assertNotIn(email, navbar.text)