conftest.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import importlib
  2. import os
  3. import shutil
  4. from pathlib import Path
  5. from typing import Dict, Generator
  6. import icecream
  7. import pytest
  8. from selenium import webdriver
  9. from selenium.webdriver.chrome.service import Service
  10. from starlette.routing import Route
  11. from nicegui import Client, app, binding, core
  12. from nicegui.page import page
  13. from .screen import Screen
  14. # pylint: disable=redefined-outer-name
  15. DOWNLOAD_DIR = Path(__file__).parent / 'download'
  16. icecream.install()
  17. @pytest.fixture
  18. def chrome_options(chrome_options: webdriver.ChromeOptions) -> webdriver.ChromeOptions:
  19. """Configure the Chrome driver options."""
  20. chrome_options.add_argument('disable-dev-shm-using')
  21. chrome_options.add_argument('no-sandbox')
  22. chrome_options.add_argument('headless')
  23. # check if we are running on GitHub Actions
  24. if 'GITHUB_ACTIONS' in os.environ:
  25. chrome_options.add_argument('disable-gpu')
  26. else:
  27. chrome_options.add_argument('--use-gl=angle')
  28. chrome_options.add_argument('window-size=600x600')
  29. chrome_options.add_experimental_option('prefs', {
  30. "download.default_directory": str(DOWNLOAD_DIR),
  31. "download.prompt_for_download": False, # To auto download the file
  32. "download.directory_upgrade": True,
  33. })
  34. if 'CHROME_BINARY_LOCATION' in os.environ:
  35. chrome_options.binary_location = os.environ['CHROME_BINARY_LOCATION']
  36. return chrome_options
  37. @pytest.fixture
  38. def capabilities(capabilities: Dict) -> Dict:
  39. """Configure the Chrome driver capabilities."""
  40. capabilities['goog:loggingPrefs'] = {'browser': 'ALL'}
  41. return capabilities
  42. @pytest.fixture(autouse=True)
  43. def reset_globals() -> Generator[None, None, None]:
  44. """Reset the global state of the NiceGUI package."""
  45. for route in app.routes:
  46. if isinstance(route, Route) and route.path.startswith('/_nicegui/auto/static/'):
  47. app.remove_route(route.path)
  48. for path in {'/'}.union(Client.page_routes.values()):
  49. app.remove_route(path)
  50. app.openapi_schema = None
  51. app.middleware_stack = None
  52. app.user_middleware.clear()
  53. # NOTE favicon routes must be removed separately because they are not "pages"
  54. for route in app.routes:
  55. if isinstance(route, Route) and route.path.endswith('/favicon.ico'):
  56. app.routes.remove(route)
  57. importlib.reload(core)
  58. Client.instances.clear()
  59. Client.page_routes.clear()
  60. Client.auto_index_client = Client(page('/'), shared=True).__enter__()
  61. app.reset()
  62. # NOTE we need to re-add the auto index route because we removed all routes above
  63. app.get('/')(Client.auto_index_client.build_response)
  64. binding.reset()
  65. yield
  66. @pytest.fixture(scope='session', autouse=True)
  67. def remove_all_screenshots() -> None:
  68. """Remove all screenshots from the screenshot directory before the test session."""
  69. if os.path.exists(Screen.SCREENSHOT_DIR):
  70. for name in os.listdir(Screen.SCREENSHOT_DIR):
  71. os.remove(os.path.join(Screen.SCREENSHOT_DIR, name))
  72. @pytest.fixture(scope='function')
  73. def driver(chrome_options: webdriver.ChromeOptions) -> webdriver.Chrome:
  74. """Create a new Chrome driver instance."""
  75. s = Service()
  76. driver_ = webdriver.Chrome(service=s, options=chrome_options)
  77. driver_.implicitly_wait(Screen.IMPLICIT_WAIT)
  78. driver_.set_page_load_timeout(4)
  79. yield driver_
  80. driver_.quit()
  81. @pytest.fixture
  82. def screen(driver: webdriver.Chrome, request: pytest.FixtureRequest, caplog: pytest.LogCaptureFixture) \
  83. -> Generator[Screen, None, None]:
  84. """Create a new Screen instance."""
  85. screen_ = Screen(driver, caplog)
  86. yield screen_
  87. if screen_.is_open:
  88. screen_.shot(request.node.name)
  89. logs = screen_.caplog.get_records('call')
  90. screen_.stop_server()
  91. if DOWNLOAD_DIR.exists():
  92. shutil.rmtree(DOWNLOAD_DIR)
  93. if logs:
  94. pytest.fail('There were unexpected logs. See "Captured log call" below.', pytrace=False)