test_shiki_code.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import pytest
  2. from reflex.components.datadisplay.shiki_code_block import (
  3. ShikiBaseTransformers,
  4. ShikiCodeBlock,
  5. ShikiHighLevelCodeBlock,
  6. ShikiJsTransformer,
  7. )
  8. from reflex.components.el.elements.forms import Button
  9. from reflex.components.lucide.icon import Icon
  10. from reflex.components.radix.themes.layout.box import Box
  11. from reflex.style import Style
  12. from reflex.vars import Var
  13. @pytest.mark.parametrize(
  14. "library, fns, expected_output, raises_exception",
  15. [
  16. ("some_library", ["function_one"], ["function_one"], False),
  17. ("some_library", [123], None, True),
  18. ("some_library", [], [], False),
  19. (
  20. "some_library",
  21. ["function_one", "function_two"],
  22. ["function_one", "function_two"],
  23. False,
  24. ),
  25. ("", ["function_one"], ["function_one"], False),
  26. ("some_library", ["function_one", 789], None, True),
  27. ("", [], [], False),
  28. ],
  29. )
  30. def test_create_transformer(library, fns, expected_output, raises_exception):
  31. if raises_exception:
  32. # Ensure ValueError is raised for invalid cases
  33. with pytest.raises(ValueError):
  34. ShikiCodeBlock.create_transformer(library, fns)
  35. else:
  36. transformer = ShikiCodeBlock.create_transformer(library, fns)
  37. assert isinstance(transformer, ShikiBaseTransformers)
  38. assert transformer.library == library
  39. # Verify that the functions are correctly wrapped in FunctionStringVar
  40. function_names = [str(fn) for fn in transformer.fns]
  41. assert function_names == expected_output
  42. @pytest.mark.parametrize(
  43. "code_block, children, props, expected_first_child, expected_styles",
  44. [
  45. ("print('Hello')", ["print('Hello')"], {}, "print('Hello')", {}),
  46. (
  47. "print('Hello')",
  48. ["print('Hello')", "More content"],
  49. {},
  50. "print('Hello')",
  51. {},
  52. ),
  53. (
  54. "print('Hello')",
  55. ["print('Hello')"],
  56. {
  57. "transformers": [
  58. ShikiBaseTransformers(
  59. library="lib", fns=[], style=Style({"color": "red"})
  60. )
  61. ]
  62. },
  63. "print('Hello')",
  64. {"color": "red"},
  65. ),
  66. (
  67. "print('Hello')",
  68. ["print('Hello')"],
  69. {
  70. "transformers": [
  71. ShikiBaseTransformers(
  72. library="lib", fns=[], style=Style({"color": "red"})
  73. )
  74. ],
  75. "style": {"background": "blue"},
  76. },
  77. "print('Hello')",
  78. {"color": "red", "background": "blue"},
  79. ),
  80. ],
  81. )
  82. def test_create_shiki_code_block(
  83. code_block, children, props, expected_first_child, expected_styles
  84. ):
  85. component = ShikiCodeBlock.create(code_block, *children, **props)
  86. # Test that the created component is a Box
  87. assert isinstance(component, Box)
  88. # Test that the first child is the code
  89. code_block_component = component.children[0]
  90. assert code_block_component.code._var_value == expected_first_child # type: ignore
  91. applied_styles = component.style
  92. for key, value in expected_styles.items():
  93. assert Var.create(applied_styles[key])._var_value == value
  94. @pytest.mark.parametrize(
  95. "children, props, expected_transformers, expected_button_type",
  96. [
  97. (["print('Hello')"], {"use_transformers": True}, [ShikiJsTransformer], None),
  98. (["print('Hello')"], {"can_copy": True}, None, Button),
  99. (
  100. ["print('Hello')"],
  101. {
  102. "can_copy": True,
  103. "copy_button": Button.create(Icon.create(tag="a_arrow_down")),
  104. },
  105. None,
  106. Button,
  107. ),
  108. ],
  109. )
  110. def test_create_shiki_high_level_code_block(
  111. children, props, expected_transformers, expected_button_type
  112. ):
  113. component = ShikiHighLevelCodeBlock.create(*children, **props)
  114. # Test that the created component is a Box
  115. assert isinstance(component, Box)
  116. # Test that the first child is the code block component
  117. code_block_component = component.children[0]
  118. assert code_block_component.code._var_value == children[0] # type: ignore
  119. # Check if the transformer is set correctly if expected
  120. if expected_transformers:
  121. exp_trans_names = [t.__name__ for t in expected_transformers]
  122. for transformer in code_block_component.transformers._var_value: # type: ignore
  123. assert type(transformer).__name__ in exp_trans_names
  124. # Check if the second child is the copy button if can_copy is True
  125. if props.get("can_copy", False):
  126. if props.get("copy_button"):
  127. assert isinstance(component.children[1], expected_button_type)
  128. assert component.children[1] == props["copy_button"]
  129. else:
  130. assert isinstance(component.children[1], expected_button_type)
  131. else:
  132. assert len(component.children) == 1
  133. @pytest.mark.parametrize(
  134. "children, props",
  135. [
  136. (["print('Hello')"], {"theme": "dark"}),
  137. (["print('Hello')"], {"language": "javascript"}),
  138. ],
  139. )
  140. def test_shiki_high_level_code_block_theme_language_mapping(children, props):
  141. component = ShikiHighLevelCodeBlock.create(*children, **props)
  142. # Test that the theme is mapped correctly
  143. if "theme" in props:
  144. assert component.children[
  145. 0
  146. ].theme._var_value == ShikiHighLevelCodeBlock._map_themes(props["theme"]) # type: ignore
  147. # Test that the language is mapped correctly
  148. if "language" in props:
  149. assert component.children[
  150. 0
  151. ].language._var_value == ShikiHighLevelCodeBlock._map_languages( # type: ignore
  152. props["language"]
  153. )