1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
from typing import Type, TypeVar, Dict
import pytest
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
TypeLiveClient = TypeVar('TypeLiveClient', bound='LiveClient')
@pytest.fixture()
def liveserver() -> Type['LiveServer']:
"""Runs a live server. Available as a context manager.
.. warning:: For Django >= 4.0
Example::
def test_live(liveserver):
with liveserver() as server:
print(f'Live server is available at: {server.url}')
"""
return LiveServer
@pytest.fixture()
def liveclient():
"""Runs a live client. Available as a context manager.
Example::
def test_live(liveserver, liveclient):
with liveserver() as server:
# Let's run Firefox using Selenium.
with liveclient('selenium', browser='firefox') as client:
selenium = client.handle # Selenium driver is available in .handle
# Let's open server's root URL and check heading 1 on that page
selenium.get(server.url)
assert selenium.find_element('tag name', 'h1').text == 'Not Found'
"""
def get_client(typename: str, *, browser: str) -> TypeLiveClient:
return LiveClient.spawn(alias=typename, browser=browser)
return get_client
class LiveServer:
_cls = StaticLiveServerTestCase
def __init__(self, *, host: str = None, port: int = None):
cls = self._cls
if host:
cls.host = host
if port is not None:
cls.port = port
@property
def url(self) -> str:
"""URL to access this live server."""
return self._cls.live_server_url
def __enter__(self):
self._cls._start_server_thread()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._cls._terminate_thread()
class LiveClient:
"""Base class for live clients."""
alias: str = ''
_registry: Dict[str, TypeLiveClient] = {}
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
alias = cls.alias
if alias:
cls._registry[alias] = cls
def __init__(self, *, browser: str):
self._browser = browser
self.handle = None
def __enter__(self) -> TypeLiveClient:
self.handle = self._handle_init()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._handle_destroy()
@classmethod
def spawn(cls, alias: str, **kwargs) -> TypeLiveClient:
client_cls = LiveClient._registry[alias]
return client_cls(**kwargs)
def _handle_init(self): # pragma: nocover
raise NotImplementedError
def _handle_destroy(self):
pass
class SeleniumLiveClient(LiveClient):
"""This live client wraps Selenium.
https://selenium-python.readthedocs.io/
"""
alias: str = 'selenium'
def _handle_init(self):
from django.test.selenium import SeleniumTestCaseBase
cls = SeleniumTestCaseBase
browser = self._browser
driver_cls = cls.import_webdriver(browser)
return driver_cls(options=cls.import_options(browser)())
def _handle_destroy(self):
handle = self.handle
if handle:
handle.quit()
super()._handle_destroy()
|