1
0

test_component.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. from typing import List, Set, Type
  2. import pytest
  3. from pynecone.components.component import Component, ImportDict
  4. from pynecone.event import EVENT_TRIGGERS, EventHandler
  5. from pynecone.state import State
  6. from pynecone.style import Style
  7. from pynecone.var import Var
  8. @pytest.fixture
  9. def TestState():
  10. class TestState(State):
  11. num: int
  12. return TestState
  13. @pytest.fixture
  14. def component1() -> Type[Component]:
  15. """A test component.
  16. Returns:
  17. A test component.
  18. """
  19. class TestComponent1(Component):
  20. # A test string prop.
  21. text: Var[str]
  22. # A test number prop.
  23. number: Var[int]
  24. def _get_imports(self) -> ImportDict:
  25. return {"react": {"Component"}}
  26. def _get_custom_code(self) -> str:
  27. return "console.log('component1')"
  28. return TestComponent1
  29. @pytest.fixture
  30. def component2() -> Type[Component]:
  31. """A test component.
  32. Returns:
  33. A test component.
  34. """
  35. class TestComponent2(Component):
  36. # A test list prop.
  37. arr: Var[List[str]]
  38. @classmethod
  39. def get_controlled_triggers(cls) -> Set[str]:
  40. """Test controlled triggers.
  41. Returns:
  42. Test controlled triggers.
  43. """
  44. return {"on_open", "on_close"}
  45. def _get_imports(self) -> ImportDict:
  46. return {"react-redux": {"connect"}}
  47. def _get_custom_code(self) -> str:
  48. return "console.log('component2')"
  49. return TestComponent2
  50. @pytest.fixture
  51. def on_click1() -> EventHandler:
  52. """A sample on click function.
  53. Returns:
  54. A sample on click function.
  55. """
  56. def on_click1():
  57. pass
  58. return EventHandler(fn=on_click1)
  59. @pytest.fixture
  60. def on_click2() -> EventHandler:
  61. """A sample on click function.
  62. Returns:
  63. A sample on click function.
  64. """
  65. def on_click2():
  66. pass
  67. return EventHandler(fn=on_click2)
  68. def test_set_style_attrs(component1):
  69. """Test that style attributes are set in the dict.
  70. Args:
  71. component1: A test component.
  72. """
  73. component = component1(color="white", text_align="center")
  74. assert component.style["color"] == "white"
  75. assert component.style["textAlign"] == "center"
  76. def test_create_component(component1):
  77. """Test that the component is created correctly.
  78. Args:
  79. component1: A test component.
  80. """
  81. children = [component1() for _ in range(3)]
  82. attrs = {"color": "white", "text_align": "center"}
  83. c = component1.create(*children, **attrs)
  84. assert isinstance(c, component1)
  85. assert c.children == children
  86. assert c.style == {"color": "white", "textAlign": "center"}
  87. def test_add_style(component1, component2):
  88. """Test adding a style to a component.
  89. Args:
  90. component1: A test component.
  91. component2: A test component.
  92. """
  93. style = {
  94. component1: Style({"color": "white"}),
  95. component2: Style({"color": "black"}),
  96. }
  97. c1 = component1().add_style(style) # type: ignore
  98. c2 = component2().add_style(style) # type: ignore
  99. assert c1.style["color"] == "white"
  100. assert c2.style["color"] == "black"
  101. def test_get_imports(component1, component2):
  102. """Test getting the imports of a component.
  103. Args:
  104. component1: A test component.
  105. component2: A test component.
  106. """
  107. c1 = component1.create()
  108. c2 = component2.create(c1)
  109. assert c1.get_imports() == {"react": {"Component"}}
  110. assert c2.get_imports() == {"react-redux": {"connect"}, "react": {"Component"}}
  111. def test_get_custom_code(component1, component2):
  112. """Test getting the custom code of a component.
  113. Args:
  114. component1: A test component.
  115. component2: A test component.
  116. """
  117. # Check that the code gets compiled correctly.
  118. c1 = component1.create()
  119. c2 = component2.create()
  120. assert c1.get_custom_code() == {"console.log('component1')"}
  121. assert c2.get_custom_code() == {"console.log('component2')"}
  122. # Check that nesting components compiles both codes.
  123. c1 = component1.create(c2)
  124. assert c1.get_custom_code() == {
  125. "console.log('component1')",
  126. "console.log('component2')",
  127. }
  128. # Check that code is not duplicated.
  129. c1 = component1.create(c2, c2, c1, c1)
  130. assert c1.get_custom_code() == {
  131. "console.log('component1')",
  132. "console.log('component2')",
  133. }
  134. def test_get_props(component1, component2):
  135. """Test that the props are set correctly.
  136. Args:
  137. component1: A test component.
  138. component2: A test component.
  139. """
  140. assert component1.get_props() == {"text", "number"}
  141. assert component2.get_props() == {"arr"}
  142. @pytest.mark.parametrize(
  143. "text,number",
  144. [
  145. ("", 0),
  146. ("test", 1),
  147. ("hi", -13),
  148. ],
  149. )
  150. def test_valid_props(component1, text: str, number: int):
  151. """Test that we can construct a component with valid props.
  152. Args:
  153. component1: A test component.
  154. text: A test string.
  155. number: A test number.
  156. """
  157. c = component1.create(text=text, number=number)
  158. assert c.text == text
  159. assert c.number == number
  160. @pytest.mark.parametrize(
  161. "text,number", [("", "bad_string"), (13, 1), (None, 1), ("test", [1, 2, 3])]
  162. )
  163. def test_invalid_prop_type(component1, text: str, number: int):
  164. """Test that an invalid prop type raises an error.
  165. Args:
  166. component1: A test component.
  167. text: A test string.
  168. number: A test number.
  169. """
  170. # Check that
  171. with pytest.raises(TypeError):
  172. component1.create(text=text, number=number)
  173. def test_var_props(component1, TestState):
  174. """Test that we can set a Var prop.
  175. Args:
  176. component1: A test component.
  177. TestState: A test state.
  178. """
  179. c1 = component1.create(text="hello", number=TestState.num)
  180. assert c1.number == TestState.num
  181. def test_get_controlled_triggers(component1, component2):
  182. """Test that we can get the controlled triggers of a component.
  183. Args:
  184. component1: A test component.
  185. component2: A test component.
  186. """
  187. assert component1.get_controlled_triggers() == set()
  188. assert component2.get_controlled_triggers() == {"on_open", "on_close"}
  189. def test_get_triggers(component1, component2):
  190. """Test that we can get the triggers of a component.
  191. Args:
  192. component1: A test component.
  193. component2: A test component.
  194. """
  195. assert component1.get_triggers() == EVENT_TRIGGERS
  196. assert component2.get_triggers() == {"on_open", "on_close"} | EVENT_TRIGGERS