test harness for selenium testing

This commit is contained in:
dandds 2018-10-01 12:05:44 -04:00
parent 78af50fcf0
commit 63f94deb40
9 changed files with 183 additions and 31 deletions

2
.gitignore vendored
View File

@ -45,5 +45,5 @@ config/dev.ini
# coverage output # coverage output
.coverage .coverage
# selenium # selenium testing
browserstacklocal browserstacklocal

View File

@ -1,5 +1,4 @@
[default] [default]
PGDATABASE = atat_selenium PGDATABASE = atat_selenium
REDIS_URI = redis://redishost:6379
CRL_DIRECTORY = tests/fixtures/crl CRL_DIRECTORY = tests/fixtures/crl
WTF_CSRF_ENABLED = false WTF_CSRF_ENABLED = false

View File

@ -2,4 +2,4 @@
norecursedirs = .venv .git node_modules norecursedirs = .venv .git node_modules
env = env =
D:FLASK_ENV=test D:FLASK_ENV=test
addopts = --cov=atst --cov-report term --cov-fail-under 90 addopts = --ignore=tests/acceptance/ --cov=atst --cov-report term --cov-fail-under 90

View File

@ -45,8 +45,8 @@ echo "starting BrowserStack local client..."
BSL_ID=$! BSL_ID=$!
# run example selenium script that fetches the home page # run example selenium script that fetches the home page
echo "running selenium example script" echo "running selenium tests"
pipenv run python selenium_example.py pipenv run pytest tests/acceptance -s
# kill BrowserStackLocal # kill BrowserStackLocal
kill $BSL_ID kill $BSL_ID

View File

@ -1,26 +0,0 @@
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
desired_cap = {
'browser': 'IE',
'browser_version': '10.0',
'os': 'Windows',
'os_version': '7',
'resolution': '1024x768',
'browserstack.local': True
}
print("initializing the webdriver")
driver = webdriver.Remote(
command_executor='http://{}:{}@hub.browserstack.com:80/wd/hub'.format(os.getenv("BROWSERSTACK_EMAIL"), os.getenv("BROWSERSTACK_TOKEN")),
desired_capabilities=desired_cap)
print("fetching the localhost page")
driver.get("http://localhost:8000")
if not "JEDI" in driver.title:
raise Exception("NO JEDI")
print("this is the page title: {}".format(driver.title))
driver.quit()
print("exiting")

View File

View File

@ -0,0 +1,67 @@
import os
import pytest
import logging
from logging.handlers import RotatingFileHandler
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from .live_server import LiveServer
@pytest.fixture(scope="session")
def live_app(app):
handler = RotatingFileHandler('log/acceptance.log', maxBytes=10000, backupCount=1)
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)
runnable = LiveServer(app, port=8943, timeout=10)
runnable.spawn_live_server()
app.server_url = runnable.server_url
yield app
runnable.terminate()
@pytest.fixture(scope="session")
def browserstack_config():
return {
"win7_ie10": {
"browser": "IE",
"browser_version": "10.0",
"os": "Windows",
"os_version": "7",
"resolution": "1024x768",
"browserstack.local": True,
},
"iphone7": {
'browserName': 'iPhone',
'device': 'iPhone 7',
'realMobile': 'true',
'os_version': '10.3',
"browserstack.local": True,
}
}
@pytest.fixture(scope="session")
def driver_builder(browserstack_config):
def build_driver(config_key):
return webdriver.Remote(
command_executor="http://{}:{}@hub.browserstack.com:80/wd/hub".format(
os.getenv("BROWSERSTACK_EMAIL"), os.getenv("BROWSERSTACK_TOKEN")
),
desired_capabilities=browserstack_config.get(config_key),
)
return build_driver
@pytest.fixture(scope="session")
def ie10_driver(driver_builder):
driver = driver_builder("win7_ie10")
yield driver
driver.quit()

View File

@ -0,0 +1,109 @@
import gc
import multiprocessing
import socket
import socketserver
import time
from urllib.parse import urlparse, urljoin
# This is adapted from flask-testing, https://github.com/jarus/flask-testing
# Inspired by https://docs.djangoproject.com/en/dev/topics/testing/#django.test.LiveServerTestCase
class LiveServer:
def __init__(self, app, port=5000, timeout=5):
self.app = app
self._configured_port = port
self._timeout = timeout
self._port_value = multiprocessing.Value("i", self._configured_port)
@property
def server_url(self):
return "http://localhost:%s" % self._port_value.value
def spawn_live_server(self):
self._process = None
port_value = self._port_value
def worker(app, port):
# Based on solution: http://stackoverflow.com/a/27598916
# Monkey-patch the server_bind so we can determine the port bound
# by Flask. This handles the case where the port specified is `0`,
# which means that the OS chooses the port. This is the only known
# way (currently) of getting the port out of Flask once we call
# `run`.
original_socket_bind = socketserver.TCPServer.server_bind
def socket_bind_wrapper(self):
ret = original_socket_bind(self)
# Get the port and save it into the port_value, so the parent
# process can read it.
(_, port) = self.socket.getsockname()
port_value.value = port
socketserver.TCPServer.server_bind = original_socket_bind
return ret
socketserver.TCPServer.server_bind = socket_bind_wrapper
app.run(port=port, use_reloader=False)
self._process = multiprocessing.Process(
target=worker, args=(self.app, self._configured_port)
)
self._process.start()
# We must wait for the server to start listening, but give up
# after a specified maximum timeout
start_time = time.time()
while True:
elapsed_time = time.time() - start_time
if elapsed_time > self._timeout:
raise RuntimeError(
"Failed to start the server after %d seconds. " % self._timeout
)
if self._can_ping_server():
break
def _can_ping_server(self):
host, port = self.address
if port == 0:
# Port specified by the user was 0, and the OS has not yet assigned
# the proper port.
return False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
except socket.error as e:
success = False
else:
success = True
finally:
sock.close()
return success
@property
def address(self):
"""
Gets the server address used to test the connection with a socket.
Respects both the LIVESERVER_PORT config value and overriding server_url
"""
parts = urlparse(self.server_url)
host = parts.hostname
port = parts.port
if port is None:
if parts.scheme == "http":
port = 80
elif parts.scheme == "https":
port = 443
else:
raise RuntimeError("Unsupported server url scheme: %s" % parts.scheme)
return host, port
def terminate(self):
if self._process:
self._process.terminate()

View File

@ -0,0 +1,3 @@
def test_can_get_title(live_app, ie10_driver):
ie10_driver.get(live_app.server_url)
assert "JEDI" in ie10_driver.title