11import logging
22import inspect
3+ import time
4+ from socket import socket
35
46from loguru import logger
57import pytest
68from _pytest .logging import caplog as _caplog # noqa
9+ from selenium .webdriver import Chrome
10+ from selenium .webdriver .chrome .options import Options
11+
12+ import pyalect .builtins .pytest # noqa
13+
14+ import idom
15+ from idom .server import hotswap_server
16+ from idom .server .sanic import PerClientState
17+
18+
19+ # Default is an error because we want to know whether we are setting the last
20+ # error while testing. A refactor could miss the code path that catches serve
21+ # errors.
22+ default_error = NotImplementedError ()
723
824
925def pytest_collection_modifyitems (items ):
1026 for item in items :
1127 if isinstance (item , pytest .Function ):
1228 if inspect .iscoroutinefunction (item .function ):
1329 item .add_marker (pytest .mark .asyncio )
30+ if "driver" in item .fixturenames :
31+ item .add_marker ("slow" )
1432
1533
1634def pytest_addoption (parser ):
@@ -30,3 +48,100 @@ def emit(self, record):
3048 handler_id = logger .add (PropogateHandler (), format = "{message}" )
3149 yield _caplog
3250 logger .remove (handler_id )
51+
52+
53+ @pytest .fixture (scope = "session" , autouse = True )
54+ def fresh_client ():
55+ idom .client .restore ()
56+ yield
57+ idom .client .restore ()
58+
59+
60+ @pytest .fixture
61+ def display (driver , server , mount , host , port , last_server_error ):
62+ def display (element , query = "" ):
63+ mount (element )
64+ driver .get (f"http://{ host } :{ port } /client/index.html" )
65+
66+ try :
67+ yield display
68+ finally :
69+ last_error = last_server_error .get ()
70+ if last_error is default_error :
71+ msg = f"The server { server } never ran or did not set the 'last_server_error' fixture."
72+ raise NotImplementedError (msg )
73+ elif last_error is not None :
74+ raise last_error
75+
76+
77+ @pytest .fixture (scope = "session" )
78+ def driver (pytestconfig ):
79+ chrome_options = Options ()
80+
81+ if getattr (pytestconfig .option , "headless" , False ):
82+ chrome_options .headless = True
83+
84+ driver = Chrome (options = chrome_options )
85+
86+ driver .set_window_size (1080 , 800 )
87+ driver .set_page_load_timeout (3 )
88+ driver .implicitly_wait (3 )
89+
90+ try :
91+ yield driver
92+ finally :
93+ driver .quit ()
94+
95+
96+ @pytest .fixture (scope = "module" )
97+ def mount (mount_and_server ):
98+ return mount_and_server [0 ]
99+
100+
101+ @pytest .fixture (scope = "module" )
102+ def server (mount_and_server ):
103+ server = mount_and_server [1 ]
104+ time .sleep (1 )
105+ yield server
106+ server .stop ()
107+
108+
109+ @pytest .fixture (scope = "module" )
110+ def mount_and_server (server_type , host , port ):
111+ return hotswap_server (server_type , host , port , run_options = {"debug" : True })
112+
113+
114+ @pytest .fixture (scope = "module" )
115+ def server_type (last_server_error ):
116+ class ServerWithErrorCatch (PerClientState ):
117+ async def _stream_route (self , request , socket ):
118+ last_server_error .set (None )
119+ try :
120+ await super ()._stream_route (request , socket )
121+ except Exception as e :
122+ last_server_error .set (e )
123+
124+ return ServerWithErrorCatch
125+
126+
127+ @pytest .fixture (scope = "session" )
128+ def host ():
129+ return "127.0.0.1"
130+
131+
132+ @pytest .fixture (scope = "module" )
133+ def port (host ):
134+ sock = socket ()
135+ sock .bind ((host , 0 ))
136+ return sock .getsockname ()[1 ]
137+
138+
139+ @pytest .fixture (scope = "session" )
140+ def last_server_error ():
141+ return idom .Var (default_error )
142+
143+
144+ @pytest .fixture (autouse = True )
145+ def _clean_last_server_error (last_server_error ):
146+ last_server_error .set (default_error )
147+ yield
0 commit comments