test_events.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import asyncio
  2. import pytest
  3. from selenium.webdriver.common.by import By
  4. from typing_extensions import Literal
  5. from nicegui import ui
  6. from nicegui.events import ClickEventArguments
  7. from .screen import Screen
  8. def click_sync_no_args():
  9. ui.label('click_sync_no_args')
  10. def click_sync_with_args(_: ClickEventArguments):
  11. ui.label('click_sync_with_args')
  12. async def click_async_no_args():
  13. await asyncio.sleep(0.1)
  14. ui.label('click_async_no_args')
  15. async def click_async_with_args(_: ClickEventArguments):
  16. await asyncio.sleep(0.1)
  17. ui.label('click_async_with_args')
  18. async def click_lambda_with_async_and_parameters(msg: str):
  19. await asyncio.sleep(0.1)
  20. ui.label(f'click_lambda_with_async_and_parameters: {msg}')
  21. def test_click_events(screen: Screen):
  22. ui.button('click_sync_no_args', on_click=click_sync_no_args)
  23. ui.button('click_sync_with_args', on_click=click_sync_with_args)
  24. ui.button('click_async_no_args', on_click=click_async_no_args)
  25. ui.button('click_async_with_args', on_click=click_async_with_args)
  26. ui.button('click_lambda_with_async_and_parameters', on_click=lambda: click_lambda_with_async_and_parameters('works'))
  27. screen.open('/')
  28. screen.click('click_sync_no_args')
  29. screen.click('click_sync_with_args')
  30. screen.click('click_async_no_args')
  31. screen.click('click_async_with_args')
  32. screen.click('click_lambda_with_async_and_parameters')
  33. screen.should_contain('click_sync_no_args')
  34. screen.should_contain('click_sync_with_args')
  35. screen.should_contain('click_async_no_args')
  36. screen.should_contain('click_async_with_args')
  37. screen.should_contain('click_lambda_with_async_and_parameters: works')
  38. def test_generic_events(screen: Screen):
  39. ui.label('click_sync_no_args').on('click', click_sync_no_args)
  40. ui.label('click_sync_with_args').on('click', click_sync_with_args)
  41. ui.label('click_async_no_args').on('click', click_async_no_args)
  42. ui.label('click_async_with_args').on('click', click_async_with_args)
  43. screen.open('/')
  44. screen.click('click_sync_no_args')
  45. screen.click('click_sync_with_args')
  46. screen.click('click_async_no_args')
  47. screen.click('click_async_with_args')
  48. screen.should_contain('click_sync_no_args')
  49. screen.should_contain('click_sync_with_args')
  50. screen.should_contain('click_async_no_args')
  51. screen.should_contain('click_async_with_args')
  52. def test_event_with_update_before_await(screen: Screen):
  53. @ui.page('/')
  54. def page():
  55. async def update():
  56. ui.label('1')
  57. await asyncio.sleep(1.0)
  58. ui.label('2')
  59. ui.button('update', on_click=update)
  60. screen.open('/')
  61. screen.click('update')
  62. screen.should_contain('1')
  63. screen.should_not_contain('2')
  64. screen.should_contain('2')
  65. def test_event_modifiers(screen: Screen):
  66. events = []
  67. ui.input('A').on('keydown', lambda _: events.append('A'))
  68. ui.input('B').on('keydown.x', lambda _: events.append('B'))
  69. ui.input('C').on('keydown.once', lambda _: events.append('C'))
  70. ui.input('D').on('keydown.shift.x', lambda _: events.append('D'))
  71. screen.open('/')
  72. screen.selenium.find_element(By.XPATH, '//*[@aria-label="A"]').send_keys('x')
  73. screen.selenium.find_element(By.XPATH, '//*[@aria-label="B"]').send_keys('xy')
  74. screen.selenium.find_element(By.XPATH, '//*[@aria-label="C"]').send_keys('xx')
  75. screen.selenium.find_element(By.XPATH, '//*[@aria-label="D"]').send_keys('Xx')
  76. assert events == ['A', 'B', 'C', 'D']
  77. def test_throttling(screen: Screen):
  78. events = []
  79. ui.button('Test', on_click=lambda: events.append(1)).on('click', lambda: events.append(2), throttle=1)
  80. screen.open('/')
  81. screen.click('Test')
  82. screen.click('Test')
  83. screen.click('Test')
  84. assert events == [1, 2, 1, 1]
  85. screen.wait(1.1)
  86. assert events == [1, 2, 1, 1, 2]
  87. screen.click('Test')
  88. screen.click('Test')
  89. screen.click('Test')
  90. assert events == [1, 2, 1, 1, 2, 1, 2, 1, 1]
  91. def test_throttling_variants(screen: Screen):
  92. events = []
  93. value = 0
  94. ui.button('Both').on('click', lambda: events.append(value), throttle=1)
  95. ui.button('Leading').on('click', lambda: events.append(value), throttle=1, trailing_events=False)
  96. ui.button('Trailing').on('click', lambda: events.append(value), throttle=1, leading_events=False)
  97. screen.open('/')
  98. value = 1
  99. screen.click('Both')
  100. value = 2
  101. screen.click('Both')
  102. value = 3
  103. screen.click('Both')
  104. assert events == [1]
  105. screen.wait(1.1)
  106. assert events == [1, 3]
  107. events = []
  108. value = 1
  109. screen.click('Leading')
  110. value = 2
  111. screen.click('Leading')
  112. value = 3
  113. screen.click('Leading')
  114. assert events == [1]
  115. screen.wait(1.1)
  116. assert events == [1]
  117. events = []
  118. value = 1
  119. screen.click('Trailing')
  120. value = 2
  121. screen.click('Trailing')
  122. value = 3
  123. screen.click('Trailing')
  124. assert events == []
  125. screen.wait(1.1)
  126. assert events == [3]
  127. @pytest.mark.parametrize('attribute', ['disabled', 'hidden'])
  128. def test_server_side_validation(screen: Screen, attribute: Literal['disabled', 'hidden']):
  129. b = ui.button('Button', on_click=lambda: ui.label('Success'))
  130. b.disable() if attribute == 'disabled' else b.set_visibility(False)
  131. ui.button('Hack', on_click=lambda: ui.run_javascript(f'''
  132. getElement({b.id}).$emit("click", {{"id": {b.id}, "listener_id": "{list(b._event_listeners.keys())[0]}"}});
  133. ''', respond=False))
  134. screen.open('/')
  135. screen.click('Hack')
  136. screen.wait(0.5)
  137. screen.should_not_contain('Success')