test_component.py 7.5 KB

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