1
0

test_refreshable.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import asyncio
  2. from nicegui import ui
  3. from nicegui.testing import Screen
  4. def test_refreshable(screen: Screen) -> None:
  5. numbers = []
  6. @ui.refreshable
  7. def number_ui() -> None:
  8. ui.label('[' + ', '.join(str(n) for n in sorted(numbers)) + ']')
  9. number_ui()
  10. ui.button('Refresh', on_click=number_ui.refresh)
  11. screen.open('/')
  12. screen.should_contain('[]')
  13. numbers.append(1)
  14. screen.click('Refresh')
  15. screen.should_contain('[1]')
  16. numbers.append(2)
  17. screen.click('Refresh')
  18. screen.should_contain('[1, 2]')
  19. numbers.clear()
  20. screen.click('Refresh')
  21. screen.should_contain('[]')
  22. def test_async_refreshable(screen: Screen) -> None:
  23. numbers = []
  24. @ui.refreshable
  25. async def number_ui() -> None:
  26. await asyncio.sleep(0.1)
  27. ui.label('[' + ', '.join(str(n) for n in sorted(numbers)) + ']')
  28. @ui.page('/')
  29. async def index():
  30. with ui.column(): # this is necessary to reproduce bug #863
  31. await number_ui()
  32. ui.button('Refresh', on_click=number_ui.refresh)
  33. screen.open('/')
  34. screen.should_contain('[]')
  35. numbers.append(1)
  36. screen.click('Refresh')
  37. screen.should_not_contain('[]') # ensure bug #863 is fixed
  38. screen.should_contain('[1]')
  39. numbers.append(2)
  40. screen.click('Refresh')
  41. screen.should_not_contain('[]')
  42. screen.should_contain('[1, 2]')
  43. numbers.clear()
  44. screen.click('Refresh')
  45. screen.should_contain('[]')
  46. def test_multiple_targets(screen: Screen) -> None:
  47. count = 0
  48. class MyClass:
  49. def __init__(self, name: str) -> None:
  50. self.name = name
  51. self.state = 1
  52. @ui.refreshable_method
  53. def create_ui(self) -> None:
  54. nonlocal count
  55. count += 1
  56. ui.label(f'{self.name} = {self.state} ({count})')
  57. ui.button(f'increment {self.name}', on_click=self.increment)
  58. def increment(self) -> None:
  59. self.state += 1
  60. self.create_ui.refresh()
  61. a = MyClass('A')
  62. a.create_ui()
  63. b = MyClass('B')
  64. b.create_ui()
  65. screen.open('/')
  66. screen.should_contain('A = 1 (1)')
  67. screen.should_contain('B = 1 (2)')
  68. screen.click('increment A')
  69. screen.should_contain('A = 2 (3)')
  70. screen.should_contain('B = 1 (2)')
  71. screen.click('increment B')
  72. screen.should_contain('A = 2 (3)')
  73. screen.should_contain('B = 2 (4)')
  74. def test_refresh_with_arguments(screen: Screen):
  75. count = 0
  76. @ui.refreshable
  77. def some_ui(value: int):
  78. nonlocal count
  79. count += 1
  80. ui.label(f'{count=}, {value=}')
  81. some_ui(0)
  82. ui.button('refresh', on_click=some_ui.refresh)
  83. ui.button('refresh()', on_click=lambda: some_ui.refresh()) # pylint: disable=unnecessary-lambda
  84. ui.button('refresh(1)', on_click=lambda: some_ui.refresh(1))
  85. ui.button('refresh(2)', on_click=lambda: some_ui.refresh(2))
  86. ui.button('refresh(value=3)', on_click=lambda: some_ui.refresh(value=3))
  87. screen.open('/')
  88. screen.should_contain('count=1, value=0')
  89. screen.click('refresh')
  90. screen.should_contain('count=2, value=0')
  91. screen.click('refresh()')
  92. screen.should_contain('count=3, value=0')
  93. screen.click('refresh(1)')
  94. screen.should_contain('count=4, value=1')
  95. screen.click('refresh(2)')
  96. screen.should_contain('count=5, value=2')
  97. screen.click('refresh(value=3)')
  98. screen.wait(0.5)
  99. screen.assert_py_logger(
  100. 'ERROR', "'value' needs to be consistently passed to some_ui() either as positional or as keyword argument")
  101. def test_refresh_deleted_element(screen: Screen):
  102. @ui.refreshable
  103. def some_ui():
  104. ui.label('some text')
  105. with ui.card() as card:
  106. some_ui()
  107. ui.button('Refresh', on_click=some_ui.refresh)
  108. ui.button('Clear', on_click=card.clear)
  109. some_ui()
  110. screen.open('/')
  111. screen.should_contain('some text')
  112. screen.click('Clear')
  113. screen.click('Refresh')
  114. def test_refresh_with_function_reference(screen: Screen):
  115. # https://github.com/zauberzeug/nicegui/issues/1283
  116. class Test:
  117. def __init__(self, name):
  118. self.name = name
  119. self.count = 0
  120. self.ui()
  121. @ui.refreshable_method
  122. def ui(self):
  123. ui.notify(f'Refreshing {self.name} ({self.count})')
  124. self.count += 1
  125. ui.button(self.name, on_click=self.ui.refresh)
  126. Test('A')
  127. Test('B')
  128. screen.open('/')
  129. screen.should_contain('Refreshing A (0)')
  130. screen.should_contain('Refreshing B (0)')
  131. screen.click('A')
  132. screen.should_contain('Refreshing A (1)')
  133. screen.click('B')
  134. screen.should_contain('Refreshing B (1)')
  135. def test_refreshable_with_state(screen: Screen):
  136. @ui.refreshable
  137. def counter(title: str):
  138. count, set_count = ui.state(0)
  139. ui.label(f'{title}: {count}')
  140. ui.button(f'Increment {title}', on_click=lambda: set_count(count + 1))
  141. counter('A')
  142. counter('B')
  143. screen.open('/')
  144. screen.should_contain('A: 0')
  145. screen.should_contain('B: 0')
  146. screen.click('Increment A')
  147. screen.wait(0.5)
  148. screen.should_contain('A: 1')
  149. screen.should_contain('B: 0')
  150. screen.click('Increment B')
  151. screen.wait(0.5)
  152. screen.should_contain('A: 1')
  153. screen.should_contain('B: 1')
  154. def test_refreshable_with_return_value(screen: Screen):
  155. @ui.refreshable
  156. def number_ui() -> int:
  157. ui.label('42')
  158. return 42
  159. answer = number_ui()
  160. assert answer == 42
  161. screen.open('/')
  162. screen.should_contain('42')