test_storage.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import asyncio
  2. import warnings
  3. from pathlib import Path
  4. import httpx
  5. from nicegui import Client, app, background_tasks, ui
  6. from .screen import PORT, Screen
  7. def test_browser_data_is_stored_in_the_browser(screen: Screen):
  8. @ui.page('/')
  9. def page():
  10. app.storage.browser['count'] = app.storage.browser.get('count', 0) + 1
  11. ui.label().bind_text_from(app.storage.browser, 'count')
  12. @app.get('/count')
  13. def count():
  14. return 'count = ' + str(app.storage.browser['count'])
  15. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  16. screen.open('/')
  17. screen.should_contain('1')
  18. screen.open('/')
  19. screen.should_contain('2')
  20. screen.open('/')
  21. screen.should_contain('3')
  22. screen.open('/count')
  23. screen.should_contain('count = 3') # also works with FastAPI endpoints
  24. def test_browser_storage_supports_asyncio(screen: Screen):
  25. @ui.page('/')
  26. async def page():
  27. app.storage.browser['count'] = app.storage.browser.get('count', 0) + 1
  28. await asyncio.sleep(0.5)
  29. ui.label(app.storage.browser['count'])
  30. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  31. screen.open('/')
  32. screen.switch_to(1)
  33. screen.open('/')
  34. screen.should_contain('2')
  35. screen.switch_to(0)
  36. screen.open('/')
  37. screen.should_contain('3')
  38. def test_browser_storage_modifications_after_page_load_are_forbidden(screen: Screen):
  39. @ui.page('/')
  40. async def page(client: Client):
  41. await client.connected()
  42. try:
  43. app.storage.browser['test'] = 'data'
  44. except TypeError as e:
  45. ui.label(str(e))
  46. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  47. screen.open('/')
  48. screen.should_contain('response to the browser has already been built')
  49. def test_user_storage_modifications(screen: Screen):
  50. @ui.page('/')
  51. async def page(client: Client, delayed: bool = False):
  52. if delayed:
  53. await client.connected()
  54. app.storage.user['count'] = app.storage.user.get('count', 0) + 1
  55. ui.label().bind_text_from(app.storage.user, 'count')
  56. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  57. screen.open('/')
  58. screen.should_contain('1')
  59. screen.open('/?delayed=True')
  60. screen.should_contain('2')
  61. screen.open('/')
  62. screen.should_contain('3')
  63. async def test_access_user_storage_from_fastapi(screen: Screen):
  64. @app.get('/api')
  65. def api():
  66. app.storage.user['msg'] = 'yes'
  67. return 'OK'
  68. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  69. screen.open('/')
  70. async with httpx.AsyncClient() as http_client:
  71. response = await http_client.get(f'http://localhost:{PORT}/api')
  72. assert response.status_code == 200
  73. assert response.text == '"OK"'
  74. await asyncio.sleep(0.5) # wait for storage to be written
  75. assert next(Path('.nicegui').glob('storage_user_*.json')).read_text() == '{"msg": "yes"}'
  76. def test_access_user_storage_on_interaction(screen: Screen):
  77. @ui.page('/')
  78. async def page():
  79. if 'test_switch' not in app.storage.user:
  80. app.storage.user['test_switch'] = False
  81. ui.switch('switch').bind_value(app.storage.user, 'test_switch')
  82. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  83. screen.open('/')
  84. screen.click('switch')
  85. screen.wait(0.5)
  86. assert '{"test_switch": true}' in next(Path('.nicegui').glob('storage_user_*.json')).read_text()
  87. def test_access_user_storage_from_button_click_handler(screen: Screen):
  88. @ui.page('/')
  89. async def page():
  90. ui.button('test', on_click=app.storage.user.update(inner_function='works'))
  91. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  92. screen.open('/')
  93. screen.click('test')
  94. screen.wait(1)
  95. assert '{"inner_function": "works"}' in next(Path('.nicegui').glob('storage_user_*.json')).read_text()
  96. async def test_access_user_storage_from_background_task(screen: Screen):
  97. @ui.page('/')
  98. def page():
  99. async def subtask():
  100. await asyncio.sleep(0.1)
  101. app.storage.user['subtask'] = 'works'
  102. background_tasks.create(subtask())
  103. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  104. screen.open('/')
  105. assert '{"subtask": "works"}' in next(Path('.nicegui').glob('storage_user_*.json')).read_text()
  106. def test_user_and_general_storage_is_persisted(screen: Screen):
  107. @ui.page('/')
  108. def page():
  109. app.storage.user['count'] = app.storage.user.get('count', 0) + 1
  110. app.storage.general['count'] = app.storage.general.get('count', 0) + 1
  111. ui.label(f'user: {app.storage.user["count"]}')
  112. ui.label(f'general: {app.storage.general["count"]}')
  113. screen.ui_run_kwargs['storage_secret'] = 'just a test'
  114. screen.open('/')
  115. screen.open('/')
  116. screen.open('/')
  117. screen.should_contain('user: 3')
  118. screen.should_contain('general: 3')
  119. screen.selenium.delete_all_cookies()
  120. screen.open('/')
  121. screen.should_contain('user: 1')
  122. screen.should_contain('general: 4')
  123. def test_rapid_storage(screen: Screen):
  124. # https://github.com/zauberzeug/nicegui/issues/1099
  125. warnings.simplefilter('error')
  126. ui.button('test', on_click=lambda: (
  127. app.storage.general.update(one=1),
  128. app.storage.general.update(two=2),
  129. app.storage.general.update(three=3),
  130. ))
  131. screen.open('/')
  132. screen.click('test')
  133. screen.wait(0.5)
  134. assert '{"one": 1, "two": 2, "three": 3}' in Path('.nicegui', 'storage_general.json').read_text()