test_tailwind.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. """Test case for disabling tailwind in the config."""
  2. import functools
  3. from collections.abc import Generator
  4. import pytest
  5. from selenium.webdriver.common.by import By
  6. from reflex.testing import AppHarness
  7. PARAGRAPH_TEXT = "Tailwind Is Cool"
  8. PARAGRAPH_CLASS_NAME = "text-red-500"
  9. TEXT_RED_500_COLOR_v3 = ["rgba(239, 68, 68, 1)", "rgb(239, 68, 68)"]
  10. TEXT_RED_500_COLOR_v4 = ["oklch(0.637 0.237 25.331)"]
  11. def TailwindApp(
  12. tailwind_version: int = 0,
  13. paragraph_text: str = PARAGRAPH_TEXT,
  14. paragraph_class_name: str = PARAGRAPH_CLASS_NAME,
  15. ):
  16. """App with tailwind optionally disabled.
  17. Args:
  18. tailwind_version: Tailwind version to use. If 0, tailwind is disabled.
  19. paragraph_text: Text for the paragraph.
  20. paragraph_class_name: Tailwind class_name for the paragraph.
  21. """
  22. from pathlib import Path
  23. import reflex as rx
  24. class UnusedState(rx.State):
  25. pass
  26. def index():
  27. return rx.el.div(
  28. rx.text(paragraph_text, class_name=paragraph_class_name),
  29. rx.el.p(paragraph_text, class_name=paragraph_class_name),
  30. rx.text(paragraph_text, as_="p", class_name=paragraph_class_name),
  31. rx.el.div("Test external stylesheet", class_name="external"),
  32. id="p-content",
  33. )
  34. assets = Path(__file__).resolve().parent.parent / "assets"
  35. assets.mkdir(exist_ok=True)
  36. stylesheet = assets / "test_styles.css"
  37. stylesheet.write_text(".external { color: rgba(0, 0, 255, 0.5) }")
  38. app = rx.App(style={"font_family": "monospace"}, stylesheets=[stylesheet.name])
  39. app.add_page(index)
  40. if not tailwind_version:
  41. config = rx.config.get_config()
  42. config.tailwind = None
  43. config.plugins = []
  44. elif tailwind_version == 3:
  45. config = rx.config.get_config()
  46. config.plugins = [rx.plugins.TailwindV3Plugin()]
  47. elif tailwind_version == 4:
  48. config = rx.config.get_config()
  49. config.plugins = [rx.plugins.TailwindV4Plugin()]
  50. @pytest.fixture(
  51. params=[0, 3, 4], ids=["tailwind_disabled", "tailwind_v3", "tailwind_v4"]
  52. )
  53. def tailwind_version(request) -> int:
  54. """Tailwind version fixture.
  55. Args:
  56. request: pytest request fixture.
  57. Returns:
  58. Tailwind version to use. 0 for disabled, 3 for v3, 4 for v4.
  59. """
  60. return request.param
  61. @pytest.fixture()
  62. def tailwind_app(tmp_path, tailwind_version) -> Generator[AppHarness, None, None]:
  63. """Start TailwindApp app at tmp_path via AppHarness with tailwind disabled via config.
  64. Args:
  65. tmp_path: pytest tmp_path fixture
  66. tailwind_version: Whether tailwind is disabled for the app.
  67. Yields:
  68. running AppHarness instance
  69. """
  70. with AppHarness.create(
  71. root=tmp_path,
  72. app_source=functools.partial(TailwindApp, tailwind_version=tailwind_version),
  73. app_name="tailwind_"
  74. + ("disabled" if tailwind_version == 0 else str(tailwind_version)),
  75. ) as harness:
  76. yield harness
  77. def test_tailwind_app(tailwind_app: AppHarness, tailwind_version: bool):
  78. """Test that the app can compile without tailwind.
  79. Args:
  80. tailwind_app: AppHarness instance.
  81. tailwind_version: Tailwind version to use. If 0, tailwind is disabled.
  82. """
  83. assert tailwind_app.app_instance is not None
  84. assert tailwind_app.backend is not None
  85. driver = tailwind_app.frontend()
  86. # Assert the app is stateless.
  87. with pytest.raises(ValueError) as errctx:
  88. _ = tailwind_app.app_instance.state_manager
  89. errctx.match("The state manager has not been initialized.")
  90. # Assert content is visible (and not some error)
  91. content = driver.find_element(By.ID, "p-content")
  92. paragraphs = content.find_elements(By.TAG_NAME, "p")
  93. assert len(paragraphs) == 3
  94. for p in paragraphs:
  95. assert tailwind_app.poll_for_content(p, exp_not_equal="") == PARAGRAPH_TEXT
  96. assert p.value_of_css_property("font-family") == "monospace"
  97. if not tailwind_version:
  98. # expect default color, not "text-red-500" from tailwind utility class
  99. assert p.value_of_css_property("color") not in TEXT_RED_500_COLOR_v3
  100. elif tailwind_version == 3:
  101. # expect "text-red-500" from tailwind utility class
  102. assert p.value_of_css_property("color") in TEXT_RED_500_COLOR_v3
  103. elif tailwind_version == 4:
  104. # expect "text-red-500" from tailwind utility class
  105. assert p.value_of_css_property("color") in TEXT_RED_500_COLOR_v4
  106. # Assert external stylesheet is applying rules
  107. external = driver.find_elements(By.CLASS_NAME, "external")
  108. assert len(external) == 1
  109. for ext_div in external:
  110. assert ext_div.value_of_css_property("color") == "rgba(0, 0, 255, 0.5)"