test_hydrate_middleware.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. from typing import Any, Dict, List
  2. import pytest
  3. from pynecone.app import App
  4. from pynecone.middleware.hydrate_middleware import IS_HYDRATED, HydrateMiddleware
  5. from pynecone.state import State
  6. def exp_is_hydrated(state: State) -> Dict[str, Any]:
  7. """Expected IS_HYDRATED delta that would be emitted by HydrateMiddleware.
  8. Args:
  9. state: the State that is hydrated
  10. Returns:
  11. dict similar to that returned by `State.get_delta` with IS_HYDRATED: True
  12. """
  13. return {state.get_name(): {IS_HYDRATED: True}}
  14. class TestState(State):
  15. """A test state with no return in handler."""
  16. __test__ = False
  17. num: int = 0
  18. def test_handler(self):
  19. """Test handler."""
  20. self.num += 1
  21. class TestState2(State):
  22. """A test state with return in handler."""
  23. __test__ = False
  24. num: int = 0
  25. name: str
  26. def test_handler(self):
  27. """Test handler that calls another handler.
  28. Returns:
  29. Chain of EventHandlers
  30. """
  31. self.num += 1
  32. return self.change_name
  33. def change_name(self):
  34. """Test handler to change name."""
  35. self.name = "random"
  36. class TestState3(State):
  37. """A test state with async handler."""
  38. __test__ = False
  39. num: int = 0
  40. async def test_handler(self):
  41. """Test handler."""
  42. self.num += 1
  43. @pytest.fixture
  44. def hydrate_middleware() -> HydrateMiddleware:
  45. """Fixture creates an instance of HydrateMiddleware per test case.
  46. Returns:
  47. instance of HydrateMiddleware
  48. """
  49. return HydrateMiddleware()
  50. @pytest.mark.asyncio
  51. @pytest.mark.parametrize(
  52. "state, expected, event_fixture",
  53. [
  54. (TestState, {"test_state": {"num": 1}}, "event1"),
  55. (TestState2, {"test_state2": {"num": 1}}, "event2"),
  56. (TestState3, {"test_state3": {"num": 1}}, "event3"),
  57. ],
  58. )
  59. async def test_preprocess(state, hydrate_middleware, request, event_fixture, expected):
  60. """Test that a state hydrate event is processed correctly.
  61. Args:
  62. state: state to process event
  63. hydrate_middleware: instance of HydrateMiddleware
  64. request: pytest fixture request
  65. event_fixture: The event fixture(an Event)
  66. expected: expected delta
  67. """
  68. app = App(state=state, load_events={"index": state.test_handler})
  69. result = await hydrate_middleware.preprocess(
  70. app=app, event=request.getfixturevalue(event_fixture), state=state()
  71. )
  72. assert isinstance(result, List)
  73. assert len(result) == 3
  74. assert result[0].delta == {state().get_name(): state().dict()}
  75. assert result[1].delta == expected
  76. assert result[2].delta == exp_is_hydrated(state())
  77. @pytest.mark.asyncio
  78. async def test_preprocess_multiple_load_events(hydrate_middleware, event1):
  79. """Test that a state hydrate event for multiple on-load events is processed correctly.
  80. Args:
  81. hydrate_middleware: instance of HydrateMiddleware
  82. event1: an Event.
  83. """
  84. app = App(
  85. state=TestState,
  86. load_events={"index": [TestState.test_handler, TestState.test_handler]},
  87. )
  88. result = await hydrate_middleware.preprocess(
  89. app=app, event=event1, state=TestState()
  90. )
  91. assert isinstance(result, List)
  92. assert len(result) == 4
  93. assert result[0].delta == {"test_state": TestState().dict()}
  94. assert result[1].delta == {"test_state": {"num": 1}}
  95. assert result[2].delta == {"test_state": {"num": 2}}
  96. assert result[3].delta == exp_is_hydrated(TestState())
  97. @pytest.mark.asyncio
  98. async def test_preprocess_no_events(hydrate_middleware, event1):
  99. """Test that app without on_load is processed correctly.
  100. Args:
  101. hydrate_middleware: instance of HydrateMiddleware
  102. event1: an Event.
  103. """
  104. result = await hydrate_middleware.preprocess(
  105. app=App(state=TestState),
  106. event=event1,
  107. state=TestState(),
  108. )
  109. assert isinstance(result, List)
  110. assert len(result) == 2
  111. assert result[0].delta == {"test_state": TestState().dict()}
  112. assert result[1].delta == exp_is_hydrated(TestState())