Skip to content

Commit 789e512

Browse files
authored
Ensure proper cleanup and error handling in test fixtures (zauberzeug#5287)
### Motivation If an exception happens inside the fixture setup, the fixture was not reset correctly leading to failed tests. ### Implementation - Updated `screen` and `user` fixtures to use `try...finally` for resource cleanup, ensuring environment variables are reset and servers are stopped even if an error occurs. - Improved error logging by checking for unexpected ERROR logs after yielding the fixture. - reactivate tests from `test_main_file_marker.py` (which failed before) This change enhances the reliability of the testing framework by ensuring that resources are properly managed and that errors are logged appropriately. ### Progress - [x] I chose a meaningful title that completes the sentence: "If applied, this PR will..." - [x] The implementation is complete. - [x] Pytests have been reactivated. - [x] Documentation is not necessary.
1 parent e311012 commit 789e512

File tree

3 files changed

+39
-35
lines changed

3 files changed

+39
-35
lines changed

nicegui/testing/screen_plugin.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,17 @@ def screen(nicegui_reset_globals, # noqa: F811, pylint: disable=unused-argument
8282
"""Create a new SeleniumScreen fixture."""
8383
os.environ['NICEGUI_SCREEN_TEST_PORT'] = str(Screen.PORT)
8484
screen_ = Screen(nicegui_driver, caplog, request)
85-
yield screen_
86-
os.environ.pop('NICEGUI_SCREEN_TEST_PORT', None)
87-
logs = [record for record in screen_.caplog.get_records('call') if record.levelname == 'ERROR']
88-
if screen_.is_open:
89-
test_failed = hasattr(request.node, 'rep_call') and request.node.rep_call.failed
90-
screen_.shot(request.node.name, failed=test_failed or bool(logs))
91-
screen_.stop_server()
92-
if DOWNLOAD_DIR.exists():
93-
shutil.rmtree(DOWNLOAD_DIR)
94-
if logs:
95-
pytest.fail('There were unexpected ERROR logs.', pytrace=False)
85+
try:
86+
yield screen_
87+
88+
logs = [record for record in screen_.caplog.get_records('call') if record.levelname == 'ERROR']
89+
if screen_.is_open:
90+
test_failed = hasattr(request.node, 'rep_call') and request.node.rep_call.failed
91+
screen_.shot(request.node.name, failed=test_failed or bool(logs))
92+
if logs:
93+
pytest.fail('There were unexpected ERROR logs.', pytrace=False)
94+
finally:
95+
os.environ.pop('NICEGUI_SCREEN_TEST_PORT', None)
96+
screen_.stop_server()
97+
if DOWNLOAD_DIR.exists():
98+
shutil.rmtree(DOWNLOAD_DIR)

nicegui/testing/user_plugin.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,36 @@ async def user(nicegui_reset_globals, # noqa: F811, pylint: disable=unused-argu
3030
) -> AsyncGenerator[User, None]:
3131
"""Create a new user fixture."""
3232
os.environ['NICEGUI_USER_SIMULATION'] = 'true'
33-
main_path = get_path_to_main_file(request)
34-
if main_path is None:
35-
prepare_simulation()
36-
ui.run(storage_secret='simulated secret')
37-
else:
38-
runpy.run_path(str(main_path), run_name='__main__')
33+
try:
34+
main_path = get_path_to_main_file(request)
35+
if main_path is None:
36+
prepare_simulation()
37+
ui.run(storage_secret='simulated secret')
38+
else:
39+
runpy.run_path(str(main_path), run_name='__main__')
3940

40-
async with core.app.router.lifespan_context(core.app):
41-
async with httpx.AsyncClient(transport=httpx.ASGITransport(core.app), base_url='http://test') as client:
42-
yield User(client)
41+
async with core.app.router.lifespan_context(core.app):
42+
async with httpx.AsyncClient(transport=httpx.ASGITransport(core.app), base_url='http://test') as client:
43+
yield User(client)
4344

44-
os.environ.pop('NICEGUI_USER_SIMULATION', None)
45-
ui.navigate = Navigate()
46-
ui.notify = notify
47-
ui.download = download
48-
49-
logs = [record for record in caplog.get_records('call') if record.levelname == 'ERROR']
50-
if logs:
51-
pytest.fail('There were unexpected ERROR logs.', pytrace=False)
45+
logs = [record for record in caplog.get_records('call') if record.levelname == 'ERROR']
46+
if logs:
47+
pytest.fail('There were unexpected ERROR logs.', pytrace=False)
48+
finally:
49+
os.environ.pop('NICEGUI_USER_SIMULATION', None)
50+
ui.navigate = Navigate()
51+
ui.notify = notify
52+
ui.download = download
5253

5354

5455
@pytest.fixture
5556
async def create_user(user: User) -> AsyncGenerator[Callable[[], User], None]: # pylint: disable=unused-argument
5657
"""Create a fixture for building new users."""
5758
prepare_simulation()
58-
async with core.app.router.lifespan_context(core.app):
59-
yield lambda: User(httpx.AsyncClient(transport=httpx.ASGITransport(core.app), base_url='http://test'))
60-
ui.navigate = Navigate()
61-
ui.notify = notify
62-
ui.download = download
59+
try:
60+
async with core.app.router.lifespan_context(core.app):
61+
yield lambda: User(httpx.AsyncClient(transport=httpx.ASGITransport(core.app), base_url='http://test'))
62+
finally:
63+
ui.navigate = Navigate()
64+
ui.notify = notify
65+
ui.download = download

tests/test_main_file_marker.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
from nicegui.testing import Screen, User
44

55

6-
@pytest.mark.skip('This test breaks all following tests')
76
@pytest.mark.xfail(raises=FileNotFoundError, strict=True)
87
@pytest.mark.nicegui_main_file('non_existent_file.py')
98
async def test_marker_injects_main_file_for_user_plugin(user: User):
109
await user.open('/')
1110

1211

13-
@pytest.mark.skip('This test breaks all following tests')
1412
@pytest.mark.xfail(raises=FileNotFoundError, strict=True)
1513
@pytest.mark.nicegui_main_file('non_existent_file.py')
1614
def test_marker_injects_main_file_for_screen_plugin(screen: Screen):

0 commit comments

Comments
 (0)