
* use serializer system * add checks for unsupported operands * and and or are now supported * format * remove unnecessary call to JSON * put base before rest * fix failing testcase * add hinting to get static analysis to complain * damn * big changes * get typeguard from extensions * please darglint * dangit darglint * remove one from vars * add without data and use it in plotly * DARGLINT * change format for special props * add pyi * delete instances of Var.create * modify client state to work * fixed so much * remove every Var.create * delete all basevar stuff * checkpoint * fix pyi * get older python to work * dangit darglint * add simple fix to last failing testcase * remove var name unwrapped and put client state on immutable var * fix older python * fox event issues * change forms pyi * make test less strict * use rx state directly * add typeignore to page_id * implement foreach * delete .web states folder silly * update reflex chakra * fix issue when on mount or on unmount is not set * nuke Var * run pyi * import immutablevar in critical location * delete unwrap vars * bring back array ref * fix style props in app * /health endpoint for K8 Liveness and Readiness probes (#3855) * Added API Endpoint * Added API Endpoint * Added Unit Tests * Added Unit Tests * main * Apply suggestions from Code Review * Fix Ruff Formatting * Update Socket Events * Async Functions * Update find_replace (#3886) * [REF-3592]Promote `rx.progress` from radix themes (#3878) * Promote `rx.progress` from radix themes * fix pyi * add warning when accessing `rx._x.progress` * Use correct flexgen backend URL (#3891) * Remove demo template (#3888) * gitignore .web (#3885) * update overflowY in AUTO_HEIGHT_JS from hidden to scroll (#3882) * Retain mutability inside `async with self` block (#3884) When emitting a state update, restore `_self_mutable` to the value it had previously so that `yield` in the middle of `async with self` does not result in an immutable StateProxy. Fix #3869 * Include child imports in markdown component_map (#3883) If a component in the markdown component_map contains children components, use `_get_all_imports` to recursively enumerate them. Fix #3880 * [REF-3570] Remove deprecated REDIS_URL syntax (#3892) * mixin computed vars should only be applied to highest level state (#3833) * improve state hierarchy validation, drop old testing special case (#3894) * fix var dependency dicts (#3842) * Adding array to array pluck operation. (#3868) * fix initial state without cv fallback (#3670) * add fragment to foreach (#3877) * Update docker-example (#3324) * /health endpoint for K8 Liveness and Readiness probes (#3855) * Added API Endpoint * Added API Endpoint * Added Unit Tests * Added Unit Tests * main * Apply suggestions from Code Review * Fix Ruff Formatting * Update Socket Events * Async Functions * /health endpoint for K8 Liveness and Readiness probes (#3855) * Added API Endpoint * Added API Endpoint * Added Unit Tests * Added Unit Tests * main * Apply suggestions from Code Review * Fix Ruff Formatting * Update Socket Events * Async Functions * Merge branch 'main' into use-old-serializer-in-literalvar * [REF-3570] Remove deprecated REDIS_URL syntax (#3892) * /health endpoint for K8 Liveness and Readiness probes (#3855) * Added API Endpoint * Added API Endpoint * Added Unit Tests * Added Unit Tests * main * Apply suggestions from Code Review * Fix Ruff Formatting * Update Socket Events * Async Functions * [REF-3570] Remove deprecated REDIS_URL syntax (#3892) * remove extra var Co-authored-by: Masen Furer <m_github@0x26.net> * resolve typo * write better doc for var.create * return var value when we know it's literal var * fix unit test * less bloat for ToOperations * simplify ImmutableComputedVar.__get__ (#3902) * simplify ImmutableComputedVar.__get__ * ruff it --------- Co-authored-by: Samarth Bhadane <samarthbhadane119@gmail.com> Co-authored-by: Elijah Ahianyo <elijahahianyo@gmail.com> Co-authored-by: Masen Furer <m_github@0x26.net> Co-authored-by: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Co-authored-by: Vishnu Deva <vishnu.deva12@gmail.com> Co-authored-by: abulvenz <a.eismann@senbax.de>
544 lines
19 KiB
Python
544 lines
19 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Dict
|
|
|
|
import pytest
|
|
|
|
import reflex as rx
|
|
from reflex import style
|
|
from reflex.components.component import evaluate_style_namespaces
|
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
|
from reflex.style import Style
|
|
from reflex.vars import VarData
|
|
|
|
test_style = [
|
|
({"a": 1}, {"a": 1}),
|
|
({"a": LiteralVar.create("abc")}, {"a": "abc"}),
|
|
({"test_case": 1}, {"testCase": 1}),
|
|
({"test_case": {"a": 1}}, {"testCase": {"a": 1}}),
|
|
({":test_case": {"a": 1}}, {":testCase": {"a": 1}}),
|
|
({"::test_case": {"a": 1}}, {"::testCase": {"a": 1}}),
|
|
(
|
|
{"::-webkit-scrollbar": {"display": "none"}},
|
|
{"::-webkit-scrollbar": {"display": "none"}},
|
|
),
|
|
({"margin_y": "2rem"}, {"marginTop": "2rem", "marginBottom": "2rem"}),
|
|
({"marginY": "2rem"}, {"marginTop": "2rem", "marginBottom": "2rem"}),
|
|
(
|
|
{"::-webkit-scrollbar": {"bgColor": "red"}},
|
|
{"::-webkit-scrollbar": {"backgroundColor": "red"}},
|
|
),
|
|
(
|
|
{"paddingX": ["2rem", "3rem"]},
|
|
{
|
|
"paddingInlineStart": ["2rem", "3rem"],
|
|
"paddingInlineEnd": ["2rem", "3rem"],
|
|
},
|
|
),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"style_dict,expected",
|
|
test_style,
|
|
)
|
|
def test_convert(style_dict, expected):
|
|
"""Test Format a style dictionary.
|
|
|
|
Args:
|
|
style_dict: The style to check.
|
|
expected: The expected formatted style.
|
|
"""
|
|
converted_dict, _var_data = style.convert(style_dict)
|
|
assert LiteralVar.create(converted_dict).equals(LiteralVar.create(expected))
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"style_dict,expected",
|
|
test_style,
|
|
)
|
|
def test_create_style(style_dict, expected):
|
|
"""Test style dictionary.
|
|
|
|
Args:
|
|
style_dict: The style to check.
|
|
expected: The expected formatted style.
|
|
"""
|
|
assert LiteralVar.create(style.Style(style_dict)).equals(
|
|
LiteralVar.create(expected)
|
|
)
|
|
|
|
|
|
def compare_dict_of_var(d1: dict[str, Any], d2: dict[str, Any]):
|
|
"""Compare two dictionaries of Var objects.
|
|
|
|
Args:
|
|
d1: The first dictionary.
|
|
d2: The second dictionary.
|
|
"""
|
|
assert len(d1) == len(d2)
|
|
for key, value in d1.items():
|
|
assert key in d2
|
|
if isinstance(value, dict):
|
|
compare_dict_of_var(value, d2[key])
|
|
elif isinstance(value, ImmutableVar):
|
|
assert value.equals(d2[key])
|
|
else:
|
|
assert value == d2[key]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("kwargs", "style_dict", "expected_get_style"),
|
|
[
|
|
({}, {}, {}),
|
|
(
|
|
{"color": "hotpink"},
|
|
{},
|
|
{"css": LiteralVar.create(Style({"color": "hotpink"}))},
|
|
),
|
|
({}, {"color": "red"}, {"css": LiteralVar.create(Style({"color": "red"}))}),
|
|
(
|
|
{"color": "hotpink"},
|
|
{"color": "red"},
|
|
{"css": LiteralVar.create(Style({"color": "hotpink"}))},
|
|
),
|
|
(
|
|
{"_hover": {"color": "hotpink"}},
|
|
{},
|
|
{"css": LiteralVar.create(Style({"&:hover": {"color": "hotpink"}}))},
|
|
),
|
|
(
|
|
{},
|
|
{"_hover": {"color": "red"}},
|
|
{"css": LiteralVar.create(Style({"&:hover": {"color": "red"}}))},
|
|
),
|
|
(
|
|
{},
|
|
{":hover": {"color": "red"}},
|
|
{"css": LiteralVar.create(Style({"&:hover": {"color": "red"}}))},
|
|
),
|
|
(
|
|
{},
|
|
{"::-webkit-scrollbar": {"display": "none"}},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style({"&::-webkit-scrollbar": {"display": "none"}})
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{},
|
|
{"::-moz-progress-bar": {"background_color": "red"}},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style({"&::-moz-progress-bar": {"backgroundColor": "red"}})
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{"color": ["#111", "#222", "#333", "#444", "#555"]},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"@media screen and (min-width: 0)": {"color": "#111"},
|
|
"@media screen and (min-width: 30em)": {"color": "#222"},
|
|
"@media screen and (min-width: 48em)": {"color": "#333"},
|
|
"@media screen and (min-width: 62em)": {"color": "#444"},
|
|
"@media screen and (min-width: 80em)": {"color": "#555"},
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"color": ["#111", "#222", "#333", "#444", "#555"],
|
|
"background_color": "#FFF",
|
|
},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"@media screen and (min-width: 0)": {"color": "#111"},
|
|
"@media screen and (min-width: 30em)": {"color": "#222"},
|
|
"@media screen and (min-width: 48em)": {"color": "#333"},
|
|
"@media screen and (min-width: 62em)": {"color": "#444"},
|
|
"@media screen and (min-width: 80em)": {"color": "#555"},
|
|
"backgroundColor": "#FFF",
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"color": ["#111", "#222", "#333", "#444", "#555"],
|
|
"background_color": ["#FFF", "#EEE", "#DDD", "#CCC", "#BBB"],
|
|
},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"@media screen and (min-width: 0)": {
|
|
"color": "#111",
|
|
"backgroundColor": "#FFF",
|
|
},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": "#222",
|
|
"backgroundColor": "#EEE",
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333",
|
|
"backgroundColor": "#DDD",
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444",
|
|
"backgroundColor": "#CCC",
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555",
|
|
"backgroundColor": "#BBB",
|
|
},
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"_hover": [
|
|
{"color": "#111"},
|
|
{"color": "#222"},
|
|
{"color": "#333"},
|
|
{"color": "#444"},
|
|
{"color": "#555"},
|
|
]
|
|
},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {"color": "#111"},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": "#222"
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333"
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444"
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555"
|
|
},
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{"_hover": {"color": ["#111", "#222", "#333", "#444", "#555"]}},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {"color": "#111"},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": "#222"
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333"
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444"
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555"
|
|
},
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"_hover": {
|
|
"color": ["#111", "#222", "#333", "#444", "#555"],
|
|
"background_color": ["#FFF", "#EEE", "#DDD", "#CCC", "#BBB"],
|
|
}
|
|
},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {
|
|
"color": "#111",
|
|
"backgroundColor": "#FFF",
|
|
},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": "#222",
|
|
"backgroundColor": "#EEE",
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333",
|
|
"backgroundColor": "#DDD",
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444",
|
|
"backgroundColor": "#CCC",
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555",
|
|
"backgroundColor": "#BBB",
|
|
},
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"_hover": {
|
|
"color": ["#111", "#222", "#333", "#444", "#555"],
|
|
"background_color": "#FFF",
|
|
}
|
|
},
|
|
{},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {"color": "#111"},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": "#222"
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333"
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444"
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555"
|
|
},
|
|
"backgroundColor": "#FFF",
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
],
|
|
)
|
|
def test_style_via_component(
|
|
kwargs: dict[str, Any],
|
|
style_dict: dict[str, Any],
|
|
expected_get_style: dict[str, Any],
|
|
):
|
|
"""Pass kwargs and style_dict to a component and assert the final, combined style dict.
|
|
|
|
Args:
|
|
kwargs: The kwargs to pass to the component.
|
|
style_dict: The style_dict to pass to the component.
|
|
expected_get_style: The expected style dict.
|
|
"""
|
|
comp = rx.el.div(style=style_dict, **kwargs) # type: ignore
|
|
compare_dict_of_var(comp._get_style(), expected_get_style)
|
|
|
|
|
|
class StyleState(rx.State):
|
|
"""Style vars in a substate."""
|
|
|
|
color: str = "hotpink"
|
|
color2: str = "red"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("kwargs", "expected_get_style"),
|
|
[
|
|
(
|
|
{"color": StyleState.color},
|
|
{"css": LiteralVar.create(Style({"color": StyleState.color}))},
|
|
),
|
|
(
|
|
{"color": f"dark{StyleState.color}"},
|
|
{
|
|
"css": ImmutableVar.create_safe(
|
|
f'({{ ["color"] : ("dark"+{StyleState.color}) }})'
|
|
).to(Dict[str, str])
|
|
},
|
|
),
|
|
(
|
|
{"color": StyleState.color, "_hover": {"color": StyleState.color2}},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"color": StyleState.color,
|
|
"&:hover": {"color": StyleState.color2},
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{"color": [StyleState.color, "gray", StyleState.color2, "yellow", "blue"]},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"@media screen and (min-width: 0)": {
|
|
"color": StyleState.color
|
|
},
|
|
"@media screen and (min-width: 30em)": {"color": "gray"},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": StyleState.color2
|
|
},
|
|
"@media screen and (min-width: 62em)": {"color": "yellow"},
|
|
"@media screen and (min-width: 80em)": {"color": "blue"},
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"_hover": [
|
|
{"color": StyleState.color},
|
|
{"color": StyleState.color2},
|
|
{"color": "#333"},
|
|
{"color": "#444"},
|
|
{"color": "#555"},
|
|
]
|
|
},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {
|
|
"color": StyleState.color
|
|
},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": StyleState.color2
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333"
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444"
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555"
|
|
},
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
(
|
|
{
|
|
"_hover": {
|
|
"color": [
|
|
StyleState.color,
|
|
StyleState.color2,
|
|
"#333",
|
|
"#444",
|
|
"#555",
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"css": LiteralVar.create(
|
|
Style(
|
|
{
|
|
"&:hover": {
|
|
"@media screen and (min-width: 0)": {
|
|
"color": StyleState.color
|
|
},
|
|
"@media screen and (min-width: 30em)": {
|
|
"color": StyleState.color2
|
|
},
|
|
"@media screen and (min-width: 48em)": {
|
|
"color": "#333"
|
|
},
|
|
"@media screen and (min-width: 62em)": {
|
|
"color": "#444"
|
|
},
|
|
"@media screen and (min-width: 80em)": {
|
|
"color": "#555"
|
|
},
|
|
}
|
|
}
|
|
)
|
|
)
|
|
},
|
|
),
|
|
],
|
|
)
|
|
def test_style_via_component_with_state(
|
|
kwargs: dict[str, Any],
|
|
expected_get_style: dict[str, Any],
|
|
):
|
|
"""Pass kwargs to a component with state vars and assert the final, combined style dict.
|
|
|
|
Args:
|
|
kwargs: The kwargs to pass to the component.
|
|
expected_get_style: The expected style dict.
|
|
"""
|
|
comp = rx.el.div(**kwargs)
|
|
|
|
assert (
|
|
VarData.merge(comp.style._var_data)
|
|
== expected_get_style["css"]._get_all_var_data()
|
|
)
|
|
# Assert that style values are equal.
|
|
compare_dict_of_var(comp._get_style(), expected_get_style)
|
|
|
|
|
|
def test_evaluate_style_namespaces():
|
|
"""Test that namespaces get converted to component create functions."""
|
|
style_dict = {rx.text: {"color": "blue"}}
|
|
assert rx.text.__call__ not in style_dict
|
|
style_dict = evaluate_style_namespaces(style_dict) # type: ignore
|
|
assert rx.text.__call__ in style_dict
|
|
|
|
|
|
def test_style_update_with_var_data():
|
|
"""Test that .update with a Style containing VarData works."""
|
|
red_var = LiteralVar.create("red")._replace(
|
|
merge_var_data=VarData(hooks={"const red = true": None}), # type: ignore
|
|
)
|
|
blue_var = LiteralVar.create("blue")._replace(
|
|
merge_var_data=VarData(hooks={"const blue = true": None}), # type: ignore
|
|
)
|
|
|
|
s1 = Style(
|
|
{
|
|
"color": red_var,
|
|
}
|
|
)
|
|
s2 = Style()
|
|
s2.update(s1, background_color=f"{blue_var}ish")
|
|
assert str(LiteralVar.create(s2)) == str(
|
|
LiteralVar.create({"color": "red", "backgroundColor": "blueish"})
|
|
)
|
|
assert s2._var_data is not None
|
|
assert "const red = true" in s2._var_data.hooks
|
|
assert "const blue = true" in s2._var_data.hooks
|