Przeglądaj źródła

logging exceptions which happen on page-ready

Rodja Trappe 2 lat temu
rodzic
commit
52dd55a4b4
4 zmienionych plików z 59 dodań i 18 usunięć
  1. 20 14
      nicegui/page.py
  2. 3 2
      tests/conftest.py
  3. 10 2
      tests/screen.py
  4. 26 0
      tests/test_pages.py

+ 20 - 14
nicegui/page.py

@@ -93,20 +93,26 @@ class Page(jp.QuasarPage):
 
     async def handle_page_ready(self, msg: AdDict) -> bool:
         with globals.within_view(self.view):
-            if self.page_ready_generator is not None:
-                if isinstance(self.page_ready_generator, types.AsyncGeneratorType):
-                    await self.page_ready_generator.asend(PageEvent(msg.websocket))
-                elif isinstance(self.page_ready_generator, types.GeneratorType):
-                    self.page_ready_generator.send(PageEvent(msg.websocket))
-            if self.page_ready_handler:
-                arg_count = len(inspect.signature(self.page_ready_handler).parameters)
-                is_coro = is_coroutine(self.page_ready_handler)
-                if arg_count == 1:
-                    await self.page_ready_handler(msg.websocket) if is_coro else self.page_ready_handler(msg.websocket)
-                elif arg_count == 0:
-                    await self.page_ready_handler() if is_coro else self.page_ready_handler()
-                else:
-                    raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
+            try:
+                if self.page_ready_generator is not None:
+                    if isinstance(self.page_ready_generator, types.AsyncGeneratorType):
+                        await self.page_ready_generator.asend(PageEvent(msg.websocket))
+                    elif isinstance(self.page_ready_generator, types.GeneratorType):
+                        self.page_ready_generator.send(PageEvent(msg.websocket))
+            except:
+                globals.log.exception('Failed to execute page-ready')
+            try:
+                if self.page_ready_handler:
+                    arg_count = len(inspect.signature(self.page_ready_handler).parameters)
+                    is_coro = is_coroutine(self.page_ready_handler)
+                    if arg_count == 1:
+                        await self.page_ready_handler(msg.websocket) if is_coro else self.page_ready_handler(msg.websocket)
+                    elif arg_count == 0:
+                        await self.page_ready_handler() if is_coro else self.page_ready_handler()
+                    else:
+                        raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
+            except:
+                globals.log.exception('Failed to execute page-ready')
         return False
 
     async def on_disconnect(self, websocket: Optional[WebSocket] = None) -> None:

+ 3 - 2
tests/conftest.py

@@ -55,8 +55,9 @@ def remove_all_screenshots() -> None:
 
 
 @pytest.fixture
-def screen(selenium: webdriver.Chrome, request: pytest.FixtureRequest) -> Generator[Screen, None, None]:
-    screen = Screen(selenium)
+def screen(selenium: webdriver.Chrome, request: pytest.FixtureRequest, caplog: pytest.LogCaptureFixture) \
+        -> Generator[Screen, None, None]:
+    screen = Screen(selenium, caplog)
     yield screen
     if screen.is_open:
         screen.shot(request.node.name)

+ 10 - 2
tests/screen.py

@@ -22,8 +22,9 @@ class Screen:
     SCREENSHOT_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'screenshots')
     UI_RUN_KWARGS = {'port': PORT, 'show': False, 'reload': False}
 
-    def __init__(self, selenium: webdriver.Chrome) -> None:
+    def __init__(self, selenium: webdriver.Chrome, caplog: pytest.LogCaptureFixture) -> None:
         self.selenium = selenium
+        self.caplog = caplog
         self.server_thread = None
 
     def start_server(self) -> None:
@@ -132,7 +133,7 @@ class Screen:
                 element.string = '... removed lengthy content ...'
         return soup.prettify()
 
-    def render_logs(self) -> str:
+    def render_js_logs(self) -> str:
         console = '\n'.join(l['message'] for l in self.selenium.get_log('browser'))
         return f'-- console logs ---\n{console}\n---------------------'
 
@@ -163,3 +164,10 @@ class Screen:
         filename = f'{self.SCREENSHOT_DIR}/{name}.png'
         print(f'Storing screenshot to {filename}')
         self.selenium.get_screenshot_as_file(filename)
+
+    def assert_py_logger(self, name: str, message: str) -> None:
+        assert len(self.caplog.records) == 1, 'Expected exactly one log message'
+        record = self.caplog.records[0]
+        print('---------------', record.levelname, record.message)
+        assert record.levelname == name, f'Expected "{name}" but got "{record.levelname}"'
+        assert record.message == message, f'Expected "{message}" but got "{record.message}"'

+ 26 - 0
tests/test_pages.py

@@ -4,6 +4,7 @@ from typing import Generator
 from uuid import uuid4
 
 import justpy.htmlcomponents
+import pytest
 from nicegui import task_logger, ui
 from nicegui.events import PageEvent
 from starlette.requests import Request
@@ -180,6 +181,7 @@ def test_shared_page_with_request_parameter_raises_exception(screen: Screen):
     screen.open('/')
     screen.should_contain('500')
     screen.should_contain('Server error')
+    screen.assert_py_logger('ERROR', 'Cannot use `request` argument in shared page')
 
 
 def test_adding_elements_in_on_page_ready_event(screen: Screen):
@@ -230,3 +232,27 @@ def test_pageready_after_yield_on_shared_page_raises_exception(screen: Screen):
     screen.open('/')
     screen.should_contain('500')
     screen.should_contain('Server error')
+    screen.assert_py_logger('ERROR', 'Yielding for page_ready is not supported on shared pages')
+
+
+def test_exception_before_yield_on_async_page(screen: Screen):
+    @ui.page('/')
+    async def page() -> Generator[None, PageEvent, None]:
+        raise Exception('some exception')
+
+    screen.open('/')
+    screen.should_contain('500')
+    screen.should_contain('Server error')
+    screen.assert_py_logger('ERROR', 'some exception')
+
+
+def test_exception_after_yield_on_async_page(screen: Screen):
+    @ui.page('/')
+    async def page() -> Generator[None, PageEvent, None]:
+        yield
+        ui.label('this is shown')
+        raise Exception('some exception')
+
+    screen.open('/')
+    screen.should_contain('this is shown')
+    screen.assert_py_logger('ERROR', 'Failed to execute page-ready')