test_input.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import asyncio
  2. from typing import Literal, Optional
  3. import pytest
  4. from selenium.webdriver.common.by import By
  5. from selenium.webdriver.common.keys import Keys
  6. from nicegui import ui
  7. from nicegui.testing import Screen
  8. def test_input(screen: Screen):
  9. ui.input('Your name', value='John Doe')
  10. screen.open('/')
  11. screen.should_contain('Your name')
  12. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Your name"]')
  13. assert element.get_attribute('type') == 'text'
  14. assert element.get_attribute('value') == 'John Doe'
  15. element.send_keys(' Jr.')
  16. assert element.get_attribute('value') == 'John Doe Jr.'
  17. def test_password(screen: Screen):
  18. ui.input('Your password', value='123456', password=True)
  19. screen.open('/')
  20. screen.should_contain('Your password')
  21. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Your password"]')
  22. assert element.get_attribute('type') == 'password'
  23. assert element.get_attribute('value') == '123456'
  24. element.send_keys('789')
  25. screen.wait(0.5)
  26. assert element.get_attribute('value') == '123456789'
  27. def test_toggle_button(screen: Screen):
  28. ui.input('Your password', value='123456', password=True, password_toggle_button=True)
  29. screen.open('/')
  30. screen.should_contain('Your password')
  31. screen.should_contain('visibility_off')
  32. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Your password"]')
  33. assert element.get_attribute('type') == 'password'
  34. assert element.get_attribute('value') == '123456'
  35. screen.click('visibility_off')
  36. screen.wait(0.5)
  37. assert element.get_attribute('type') == 'text'
  38. screen.click('visibility')
  39. screen.wait(0.5)
  40. assert element.get_attribute('type') == 'password'
  41. @pytest.mark.parametrize('method', ['dict', 'sync', 'async'])
  42. def test_input_validation(method: Literal['dict', 'sync', 'async'], screen: Screen):
  43. if method == 'sync':
  44. input_ = ui.input('Name', validation=lambda x: 'Short' if len(x) < 3 else 'Still short' if len(x) < 5 else None)
  45. elif method == 'dict':
  46. input_ = ui.input('Name', validation={'Short': lambda x: len(x) >= 3, 'Still short': lambda x: len(x) >= 5})
  47. else:
  48. async def validate(x: str) -> Optional[str]:
  49. await asyncio.sleep(0.1)
  50. return 'Short' if len(x) < 3 else 'Still short' if len(x) < 5 else None
  51. input_ = ui.input('Name', validation=validate)
  52. def assert_validation(expected: bool):
  53. if method == 'async':
  54. with pytest.raises(NotImplementedError):
  55. input_.validate()
  56. assert input_.validate(return_result=False)
  57. else:
  58. assert input_.validate() == expected
  59. screen.open('/')
  60. screen.should_contain('Name')
  61. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Name"]')
  62. element.send_keys('Jo')
  63. screen.should_contain('Short')
  64. assert input_.error == 'Short'
  65. assert_validation(False)
  66. element.send_keys('hn')
  67. screen.should_contain('Still short')
  68. assert input_.error == 'Still short'
  69. assert_validation(False)
  70. element.send_keys(' Doe')
  71. screen.wait(1.0)
  72. screen.should_not_contain('Short')
  73. screen.should_not_contain('Still short')
  74. assert input_.error is None
  75. assert_validation(True)
  76. def test_input_with_multi_word_error_message(screen: Screen):
  77. input_ = ui.input(label='some input')
  78. ui.button('set error', on_click=lambda: input_.props('error error-message="Some multi word error message"'))
  79. screen.open('/')
  80. screen.should_not_contain('Some multi word error message')
  81. screen.click('set error')
  82. screen.should_contain('Some multi word error message')
  83. def test_autocompletion(screen: Screen):
  84. input_ = ui.input('Input', autocomplete=['foo', 'bar', 'baz'])
  85. screen.open('/')
  86. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Input"]')
  87. element.send_keys('f')
  88. screen.should_contain('oo')
  89. element.send_keys('l')
  90. screen.wait(0.5)
  91. screen.should_not_contain('oo')
  92. element.send_keys(Keys.BACKSPACE)
  93. screen.should_contain('oo')
  94. element.send_keys(Keys.TAB)
  95. screen.wait(0.2)
  96. assert element.get_attribute('value') == 'foo'
  97. assert input_.value == 'foo'
  98. element.send_keys(Keys.BACKSPACE)
  99. element.send_keys(Keys.BACKSPACE)
  100. element.send_keys('x')
  101. element.send_keys(Keys.TAB)
  102. screen.wait(0.5)
  103. assert element.get_attribute('value') == 'fx'
  104. assert input_.value == 'fx'
  105. input_.set_autocomplete(['once', 'twice'])
  106. screen.wait(0.2)
  107. element.send_keys(Keys.BACKSPACE)
  108. element.send_keys(Keys.BACKSPACE)
  109. element.send_keys('o')
  110. screen.should_contain('nce')
  111. def test_clearable_input(screen: Screen):
  112. input_ = ui.input(value='foo').props('clearable')
  113. ui.label().bind_text_from(input_, 'value', lambda value: f'value: {value}')
  114. screen.open('/')
  115. screen.should_contain('value: foo')
  116. screen.click('cancel')
  117. screen.should_contain('value: None')
  118. def test_update_input(screen: Screen):
  119. input_ = ui.input('Name', value='Pete')
  120. screen.open('/')
  121. element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Name"]')
  122. assert element.get_attribute('value') == 'Pete'
  123. element.send_keys('r')
  124. screen.wait(0.5)
  125. assert element.get_attribute('value') == 'Peter'
  126. input_.value = 'Pete'
  127. screen.wait(0.5)
  128. assert element.get_attribute('value') == 'Pete'
  129. def test_switching_focus(screen: Screen):
  130. input1 = ui.input()
  131. input2 = ui.input()
  132. ui.button('focus 1', on_click=lambda: input1.run_method('focus'))
  133. ui.button('focus 2', on_click=lambda: input2.run_method('focus'))
  134. screen.open('/')
  135. elements = screen.selenium.find_elements(By.XPATH, '//input')
  136. assert len(elements) == 2
  137. screen.click('focus 1')
  138. screen.wait(0.3)
  139. assert elements[0] == screen.selenium.switch_to.active_element
  140. screen.click('focus 2')
  141. screen.wait(0.3)
  142. assert elements[1] == screen.selenium.switch_to.active_element