test_app.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import os.path
  2. from typing import List, Tuple, Type
  3. import pytest
  4. from pynecone.app import App, DefaultState
  5. from pynecone.components import Box
  6. from pynecone.event import Event
  7. from pynecone.middleware import HydrateMiddleware
  8. from pynecone.state import State
  9. from pynecone.style import Style
  10. @pytest.fixture
  11. def app() -> App:
  12. """A base app.
  13. Returns:
  14. The app.
  15. """
  16. return App()
  17. @pytest.fixture
  18. def index_page():
  19. """An index page.
  20. Returns:
  21. The index page.
  22. """
  23. def index():
  24. return Box.create("Index")
  25. return index
  26. @pytest.fixture
  27. def about_page():
  28. """An about page.
  29. Returns:
  30. The about page.
  31. """
  32. def about():
  33. return Box.create("About")
  34. return about
  35. @pytest.fixture()
  36. def TestState() -> Type[State]:
  37. """A default state.
  38. Returns:
  39. A default state.
  40. """
  41. class TestState(State):
  42. var: int
  43. return TestState
  44. def test_default_app(app: App):
  45. """Test creating an app with no args.
  46. Args:
  47. app: The app to test.
  48. """
  49. assert app.state() == DefaultState()
  50. assert app.middleware == [HydrateMiddleware()]
  51. assert app.style == Style()
  52. def test_add_page_default_route(app: App, index_page, about_page):
  53. """Test adding a page to an app.
  54. Args:
  55. app: The app to test.
  56. index_page: The index page.
  57. about_page: The about page.
  58. """
  59. assert app.pages == {}
  60. app.add_page(index_page)
  61. assert set(app.pages.keys()) == {"index"}
  62. app.add_page(about_page)
  63. assert set(app.pages.keys()) == {"index", "about"}
  64. def test_add_page_set_route(app: App, index_page, windows_platform: bool):
  65. """Test adding a page to an app.
  66. Args:
  67. app: The app to test.
  68. index_page: The index page.
  69. windows_platform: Whether the system is windows.
  70. """
  71. route = "\\test" if windows_platform else "/test"
  72. assert app.pages == {}
  73. app.add_page(index_page, route=route)
  74. assert set(app.pages.keys()) == {"test"}
  75. def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool):
  76. """Test adding a page to an app.
  77. Args:
  78. app: The app to test.
  79. index_page: The index page.
  80. windows_platform: Whether the system is windows.
  81. """
  82. route = "\\test\\nested" if windows_platform else "/test/nested"
  83. assert app.pages == {}
  84. app.add_page(index_page, route=route)
  85. assert set(app.pages.keys()) == {route.strip(os.path.sep)}
  86. def test_initialize_with_state(TestState: Type[State]):
  87. """Test setting the state of an app.
  88. Args:
  89. TestState: The default state.
  90. """
  91. app = App(state=TestState)
  92. assert app.state == TestState
  93. # Get a state for a given token.
  94. token = "token"
  95. state = app.state_manager.get_state(token)
  96. assert isinstance(state, TestState)
  97. assert state.var == 0 # type: ignore
  98. def test_set_and_get_state(TestState: Type[State]):
  99. """Test setting and getting the state of an app with different tokens.
  100. Args:
  101. TestState: The default state.
  102. """
  103. app = App(state=TestState)
  104. # Create two tokens.
  105. token1 = "token1"
  106. token2 = "token2"
  107. # Get the default state for each token.
  108. state1 = app.state_manager.get_state(token1)
  109. state2 = app.state_manager.get_state(token2)
  110. assert state1.var == 0 # type: ignore
  111. assert state2.var == 0 # type: ignore
  112. # Set the vars to different values.
  113. state1.var = 1
  114. state2.var = 2
  115. app.state_manager.set_state(token1, state1)
  116. app.state_manager.set_state(token2, state2)
  117. # Get the states again and check the values.
  118. state1 = app.state_manager.get_state(token1)
  119. state2 = app.state_manager.get_state(token2)
  120. assert state1.var == 1 # type: ignore
  121. assert state2.var == 2 # type: ignore
  122. @pytest.fixture
  123. def list_mutation_state():
  124. """A fixture to create a state with list mutation features.
  125. Returns:
  126. A state with list mutation features.
  127. """
  128. class TestState(State):
  129. """The test state."""
  130. # plain list
  131. plain_friends = ["Tommy"]
  132. def make_friend(self):
  133. self.plain_friends.append("another-fd")
  134. def change_first_friend(self):
  135. self.plain_friends[0] = "Jenny"
  136. def unfriend_all_friends(self):
  137. self.plain_friends.clear()
  138. def unfriend_first_friend(self):
  139. del self.plain_friends[0]
  140. def remove_last_friend(self):
  141. self.plain_friends.pop()
  142. def make_friends_with_colleagues(self):
  143. colleagues = ["Peter", "Jimmy"]
  144. self.plain_friends.extend(colleagues)
  145. def remove_tommy(self):
  146. self.plain_friends.remove("Tommy")
  147. # list in dict
  148. friends_in_dict = {"Tommy": ["Jenny"]}
  149. def remove_jenny_from_tommy(self):
  150. self.friends_in_dict["Tommy"].remove("Jenny")
  151. def add_jimmy_to_tommy_friends(self):
  152. self.friends_in_dict["Tommy"].append("Jimmy")
  153. def tommy_has_no_fds(self):
  154. self.friends_in_dict["Tommy"].clear()
  155. # nested list
  156. friends_in_nested_list = [["Tommy"], ["Jenny"]]
  157. def remove_first_group(self):
  158. self.friends_in_nested_list.pop(0)
  159. def remove_first_person_from_first_group(self):
  160. self.friends_in_nested_list[0].pop(0)
  161. def add_jimmy_to_second_group(self):
  162. self.friends_in_nested_list[1].append("Jimmy")
  163. return TestState()
  164. # @pytest.mark.asyncio
  165. # @pytest.mark.parametrize(
  166. # "event_tuples",
  167. # [
  168. # pytest.param(
  169. # [
  170. # (
  171. # "test_state.make_friend",
  172. # {"test_state": {"plain_friends": ["Tommy", "another-fd"]}},
  173. # ),
  174. # (
  175. # "test_state.change_first_friend",
  176. # {"test_state": {"plain_friends": ["Jenny", "another-fd"]}},
  177. # ),
  178. # ],
  179. # id="append then __setitem__",
  180. # ),
  181. # pytest.param(
  182. # [
  183. # (
  184. # "test_state.unfriend_first_friend",
  185. # {"test_state": {"plain_friends": []}},
  186. # ),
  187. # (
  188. # "test_state.make_friend",
  189. # {"test_state": {"plain_friends": ["another-fd"]}},
  190. # ),
  191. # ],
  192. # id="delitem then append",
  193. # ),
  194. # pytest.param(
  195. # [
  196. # (
  197. # "test_state.make_friends_with_colleagues",
  198. # {"test_state": {"plain_friends": ["Tommy", "Peter", "Jimmy"]}},
  199. # ),
  200. # (
  201. # "test_state.remove_tommy",
  202. # {"test_state": {"plain_friends": ["Peter", "Jimmy"]}},
  203. # ),
  204. # (
  205. # "test_state.remove_last_friend",
  206. # {"test_state": {"plain_friends": ["Peter"]}},
  207. # ),
  208. # (
  209. # "test_state.unfriend_all_friends",
  210. # {"test_state": {"plain_friends": []}},
  211. # ),
  212. # ],
  213. # id="extend, remove, pop, clear",
  214. # ),
  215. # pytest.param(
  216. # [
  217. # (
  218. # "test_state.add_jimmy_to_second_group",
  219. # {
  220. # "test_state": {
  221. # "friends_in_nested_list": [["Tommy"], ["Jenny", "Jimmy"]]
  222. # }
  223. # },
  224. # ),
  225. # (
  226. # "test_state.remove_first_person_from_first_group",
  227. # {
  228. # "test_state": {
  229. # "friends_in_nested_list": [[], ["Jenny", "Jimmy"]]
  230. # }
  231. # },
  232. # ),
  233. # (
  234. # "test_state.remove_first_group",
  235. # {"test_state": {"friends_in_nested_list": [["Jenny", "Jimmy"]]}},
  236. # ),
  237. # ],
  238. # id="nested list",
  239. # ),
  240. # pytest.param(
  241. # [
  242. # (
  243. # "test_state.add_jimmy_to_tommy_friends",
  244. # {"test_state": {"friends_in_dict": {"Tommy": ["Jenny", "Jimmy"]}}},
  245. # ),
  246. # (
  247. # "test_state.remove_jenny_from_tommy",
  248. # {"test_state": {"friends_in_dict": {"Tommy": ["Jimmy"]}}},
  249. # ),
  250. # (
  251. # "test_state.tommy_has_no_fds",
  252. # {"test_state": {"friends_in_dict": {"Tommy": []}}},
  253. # ),
  254. # ],
  255. # id="list in dict",
  256. # ),
  257. # ],
  258. # )
  259. # async def test_list_mutation_detection__plain_list(
  260. # event_tuples: List[Tuple[str, List[str]]], list_mutation_state: State
  261. # ):
  262. # """Test list mutation detection
  263. # when reassignment is not explicitly included in the logic.
  264. # Args:
  265. # event_tuples: From parametrization.
  266. # list_mutation_state: A state with list mutation features.
  267. # """
  268. # for event_name, expected_delta in event_tuples:
  269. # result = await list_mutation_state.process(
  270. # Event(
  271. # token="fake-token",
  272. # name=event_name,
  273. # router_data={"pathname": "/", "query": {}},
  274. # payload={},
  275. # )
  276. # )
  277. # assert result.delta == expected_delta