test_shiki_code.py 6.0 KB

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