test_page.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import asyncio
  2. from uuid import uuid4
  3. from nicegui import Client, background_tasks, ui
  4. from .screen import Screen
  5. def test_page(screen: Screen):
  6. @ui.page('/')
  7. def page():
  8. ui.label('Hello, world!')
  9. screen.open('/')
  10. screen.should_contain('NiceGUI')
  11. screen.should_contain('Hello, world!')
  12. def test_auto_index_page(screen: Screen):
  13. ui.label('Hello, world!')
  14. screen.open('/')
  15. screen.should_contain('NiceGUI')
  16. screen.should_contain('Hello, world!')
  17. def test_custom_title(screen: Screen):
  18. @ui.page('/', title='My Custom Title')
  19. def page():
  20. ui.label('Hello, world!')
  21. screen.open('/')
  22. screen.should_contain('My Custom Title')
  23. screen.should_contain('Hello, world!')
  24. def test_route_with_custom_path(screen: Screen):
  25. @ui.page('/test_route')
  26. def page():
  27. ui.label('page with custom path')
  28. screen.open('/test_route')
  29. screen.should_contain('page with custom path')
  30. def test_auto_index_page_with_link_to_subpage(screen: Screen):
  31. ui.link('link to subpage', '/subpage')
  32. @ui.page('/subpage')
  33. def page():
  34. ui.label('the subpage')
  35. screen.open('/')
  36. screen.click('link to subpage')
  37. screen.should_contain('the subpage')
  38. def test_link_to_page_by_passing_function(screen: Screen):
  39. @ui.page('/subpage')
  40. def page():
  41. ui.label('the subpage')
  42. ui.link('link to subpage', page)
  43. screen.open('/')
  44. screen.click('link to subpage')
  45. screen.should_contain('the subpage')
  46. def test_creating_new_page_after_startup(screen: Screen):
  47. screen.start_server()
  48. @ui.page('/late_page')
  49. def page():
  50. ui.label('page created after startup')
  51. screen.open('/late_page')
  52. screen.should_contain('page created after startup')
  53. def test_shared_and_private_pages(screen: Screen):
  54. @ui.page('/private_page')
  55. def private_page():
  56. ui.label(f'private page with uuid {uuid4()}')
  57. ui.label(f'shared page with uuid {uuid4()}')
  58. screen.open('/private_page')
  59. uuid1 = screen.find('private page').text.split()[-1]
  60. screen.open('/private_page')
  61. uuid2 = screen.find('private page').text.split()[-1]
  62. assert uuid1 != uuid2
  63. screen.open('/')
  64. uuid1 = screen.find('shared page').text.split()[-1]
  65. screen.open('/')
  66. uuid2 = screen.find('shared page').text.split()[-1]
  67. assert uuid1 == uuid2
  68. def test_wait_for_connected(screen: Screen):
  69. async def load() -> None:
  70. label.text = 'loading...'
  71. # NOTE we can not use asyncio.create_task() here because we are on a different thread than the NiceGUI event loop
  72. background_tasks.create(takes_a_while())
  73. async def takes_a_while() -> None:
  74. await asyncio.sleep(0.1)
  75. label.text = 'delayed data has been loaded'
  76. @ui.page('/')
  77. async def page(client: Client):
  78. global label
  79. label = ui.label()
  80. await client.connected()
  81. await load()
  82. screen.open('/')
  83. screen.should_contain('delayed data has been loaded')
  84. def test_wait_for_disconnect(screen: Screen):
  85. events = []
  86. @ui.page('/')
  87. async def page(client: Client):
  88. await client.connected()
  89. events.append('connected')
  90. await client.disconnected()
  91. events.append('disconnected')
  92. screen.open('/')
  93. screen.wait(0.5)
  94. screen.open('/')
  95. screen.wait(0.5)
  96. assert events == ['connected', 'disconnected', 'connected']
  97. def test_adding_elements_after_connected(screen: Screen):
  98. @ui.page('/')
  99. async def page(client: Client):
  100. ui.label('before')
  101. await client.connected()
  102. ui.label('after')
  103. screen.open('/')
  104. screen.should_contain('before')
  105. screen.should_contain('after')
  106. def test_exception(screen: Screen):
  107. @ui.page('/')
  108. def page():
  109. raise Exception('some exception')
  110. screen.open('/')
  111. screen.should_contain('500')
  112. screen.should_contain('Server error')
  113. screen.assert_py_logger('ERROR', 'some exception')
  114. def test_exception_after_connected(screen: Screen):
  115. @ui.page('/')
  116. async def page(client: Client):
  117. await client.connected()
  118. ui.label('this is shown')
  119. raise Exception('some exception')
  120. screen.open('/')
  121. screen.should_contain('this is shown')
  122. screen.assert_py_logger('ERROR', 'some exception')
  123. def test_page_with_args(screen: Screen):
  124. @ui.page('/page/{id}')
  125. def page(id: int):
  126. ui.label(f'Page {id}')
  127. screen.open('/page/42')
  128. screen.should_contain('Page 42')
  129. def test_adding_elements_during_onconnect(screen: Screen):
  130. @ui.page('/')
  131. def page(client: Client):
  132. ui.label('Label 1')
  133. client.on_connect(lambda: ui.label('Label 2'))
  134. screen.open('/')
  135. screen.should_contain('Label 2')
  136. def test_async_connect_handler(screen: Screen):
  137. @ui.page('/')
  138. def page(client: Client):
  139. async def run_js():
  140. result.text = await ui.run_javascript('41 + 1')
  141. result = ui.label()
  142. client.on_connect(run_js)
  143. screen.open('/')
  144. screen.should_contain('42')
  145. def test_dark_mode(screen: Screen):
  146. @ui.page('/auto', dark=None)
  147. def page():
  148. ui.label('A').classes('text-blue-400 dark:text-red-400')
  149. @ui.page('/light', dark=False)
  150. def page():
  151. ui.label('B').classes('text-blue-400 dark:text-red-400')
  152. @ui.page('/dark', dark=True)
  153. def page():
  154. ui.label('C').classes('text-blue-400 dark:text-red-400')
  155. blue = 'rgba(96, 165, 250, 1)'
  156. red = 'rgba(248, 113, 113, 1)'
  157. white = 'rgba(0, 0, 0, 0)'
  158. black = 'rgba(18, 18, 18, 1)'
  159. screen.open('/auto')
  160. assert screen.find('A').value_of_css_property('color') == blue
  161. assert screen.find_by_tag('body').value_of_css_property('background-color') == white
  162. screen.open('/light')
  163. assert screen.find('B').value_of_css_property('color') == blue
  164. assert screen.find_by_tag('body').value_of_css_property('background-color') == white
  165. screen.open('/dark')
  166. assert screen.find('C').value_of_css_property('color') == red
  167. assert screen.find_by_tag('body').value_of_css_property('background-color') == black