test_compiler.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import os
  2. from typing import List
  3. import pytest
  4. from reflex.compiler import compiler, utils
  5. from reflex.utils import imports
  6. from reflex.utils.imports import ImportVar
  7. @pytest.mark.parametrize(
  8. "fields,test_default,test_rest",
  9. [
  10. (
  11. [ImportVar(tag="axios", is_default=True)],
  12. "axios",
  13. [],
  14. ),
  15. (
  16. [ImportVar(tag="foo"), ImportVar(tag="bar")],
  17. "",
  18. ["bar", "foo"],
  19. ),
  20. (
  21. [
  22. ImportVar(tag="axios", is_default=True),
  23. ImportVar(tag="foo"),
  24. ImportVar(tag="bar"),
  25. ],
  26. "axios",
  27. ["bar", "foo"],
  28. ),
  29. ],
  30. )
  31. def test_compile_import_statement(
  32. fields: List[ImportVar], test_default: str, test_rest: str
  33. ):
  34. """Test the compile_import_statement function.
  35. Args:
  36. fields: The fields to import.
  37. test_default: The expected output of default library.
  38. test_rest: The expected output rest libraries.
  39. """
  40. default, rest = utils.compile_import_statement(fields)
  41. assert default == test_default
  42. assert sorted(rest) == test_rest
  43. @pytest.mark.parametrize(
  44. "import_dict,test_dicts",
  45. [
  46. ({}, []),
  47. (
  48. {"axios": [ImportVar(tag="axios", is_default=True)]},
  49. [{"lib": "axios", "default": "axios", "rest": []}],
  50. ),
  51. (
  52. {"axios": [ImportVar(tag="foo"), ImportVar(tag="bar")]},
  53. [{"lib": "axios", "default": "", "rest": ["bar", "foo"]}],
  54. ),
  55. (
  56. {
  57. "axios": [
  58. ImportVar(tag="axios", is_default=True),
  59. ImportVar(tag="foo"),
  60. ImportVar(tag="bar"),
  61. ],
  62. "react": [ImportVar(tag="react", is_default=True)],
  63. },
  64. [
  65. {"lib": "axios", "default": "axios", "rest": ["bar", "foo"]},
  66. {"lib": "react", "default": "react", "rest": []},
  67. ],
  68. ),
  69. (
  70. {"": [ImportVar(tag="lib1.js"), ImportVar(tag="lib2.js")]},
  71. [
  72. {"lib": "lib1.js", "default": "", "rest": []},
  73. {"lib": "lib2.js", "default": "", "rest": []},
  74. ],
  75. ),
  76. (
  77. {
  78. "": [ImportVar(tag="lib1.js"), ImportVar(tag="lib2.js")],
  79. "axios": [ImportVar(tag="axios", is_default=True)],
  80. },
  81. [
  82. {"lib": "lib1.js", "default": "", "rest": []},
  83. {"lib": "lib2.js", "default": "", "rest": []},
  84. {"lib": "axios", "default": "axios", "rest": []},
  85. ],
  86. ),
  87. ],
  88. )
  89. def test_compile_imports(import_dict: imports.ImportDict, test_dicts: List[dict]):
  90. """Test the compile_imports function.
  91. Args:
  92. import_dict: The import dictionary.
  93. test_dicts: The expected output.
  94. """
  95. imports = utils.compile_imports(import_dict)
  96. for import_dict, test_dict in zip(imports, test_dicts):
  97. assert import_dict["lib"] == test_dict["lib"]
  98. assert import_dict["default"] == test_dict["default"]
  99. assert sorted(import_dict["rest"]) == test_dict["rest"] # type: ignore
  100. def test_compile_stylesheets(tmp_path, mocker):
  101. """Test that stylesheets compile correctly.
  102. Args:
  103. tmp_path: The test directory.
  104. mocker: Pytest mocker object.
  105. """
  106. project = tmp_path / "test_project"
  107. project.mkdir()
  108. assets_dir = project / "assets"
  109. assets_dir.mkdir()
  110. (assets_dir / "styles.css").touch()
  111. mocker.patch("reflex.compiler.compiler.Path.cwd", return_value=project)
  112. stylesheets = [
  113. "https://fonts.googleapis.com/css?family=Sofia&effect=neon|outline|emboss|shadow-multiple",
  114. "https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css",
  115. "/styles.css",
  116. "https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css",
  117. ]
  118. assert compiler.compile_root_stylesheet(stylesheets) == (
  119. os.path.join(".web", "styles", "styles.css"),
  120. f"@import url('./tailwind.css'); \n"
  121. f"@import url('https://fonts.googleapis.com/css?family=Sofia&effect=neon|outline|emboss|shadow-multiple'); \n"
  122. f"@import url('https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'); \n"
  123. f"@import url('@/styles.css'); \n"
  124. f"@import url('https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css'); \n",
  125. )
  126. def test_compile_stylesheets_exclude_tailwind(tmp_path, mocker):
  127. """Test that Tailwind is excluded if tailwind config is explicitly set to None.
  128. Args:
  129. tmp_path: The test directory.
  130. mocker: Pytest mocker object.
  131. """
  132. project = tmp_path / "test_project"
  133. project.mkdir()
  134. assets_dir = project / "assets"
  135. assets_dir.mkdir()
  136. mock = mocker.Mock()
  137. mocker.patch.object(mock, "tailwind", None)
  138. mocker.patch("reflex.compiler.compiler.get_config", return_value=mock)
  139. (assets_dir / "styles.css").touch()
  140. mocker.patch("reflex.compiler.compiler.Path.cwd", return_value=project)
  141. stylesheets = [
  142. "/styles.css",
  143. ]
  144. assert compiler.compile_root_stylesheet(stylesheets) == (
  145. os.path.join(".web", "styles", "styles.css"),
  146. "@import url('@/styles.css'); \n",
  147. )
  148. def test_compile_nonexistent_stylesheet(tmp_path, mocker):
  149. """Test that an error is thrown for non-existent stylesheets.
  150. Args:
  151. tmp_path: The test directory.
  152. mocker: Pytest mocker object.
  153. """
  154. project = tmp_path / "test_project"
  155. project.mkdir()
  156. assets_dir = project / "assets"
  157. assets_dir.mkdir()
  158. mocker.patch("reflex.compiler.compiler.Path.cwd", return_value=project)
  159. stylesheets = ["/styles.css"]
  160. with pytest.raises(FileNotFoundError):
  161. compiler.compile_root_stylesheet(stylesheets)
  162. def test_create_document_root():
  163. """Test that the document root is created correctly."""
  164. # Test with no components.
  165. root = utils.create_document_root()
  166. assert isinstance(root, utils.Html)
  167. assert isinstance(root.children[0], utils.DocumentHead)
  168. # No children in head.
  169. assert len(root.children[0].children) == 0
  170. # Test with components.
  171. comps = [
  172. utils.NextScript.create(src="foo.js"),
  173. utils.NextScript.create(src="bar.js"),
  174. ]
  175. root = utils.create_document_root(head_components=comps) # type: ignore
  176. # Two children in head.
  177. assert len(root.children[0].children) == 2