from __future__ import annotations from typing import Any import pytest import reflex as rx from reflex import style from reflex.vars import Var test_style = [ ({"a": 1}, {"a": 1}), ({"a": Var.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"}}, ), ] @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 converted_dict == 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 style.Style(style_dict) == 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, Var): assert value.equals(d2[key]) else: assert value == d2[key] @pytest.mark.parametrize( ("kwargs", "style_dict", "expected_get_style"), [ ({}, {}, {"css": None}), ({"color": "hotpink"}, {}, {"css": Var.create({"color": "hotpink"})}), ({}, {"color": "red"}, {"css": Var.create({"color": "red"})}), ( {"color": "hotpink"}, {"color": "red"}, {"css": Var.create({"color": "hotpink"})}, ), ( {"_hover": {"color": "hotpink"}}, {}, {"css": Var.create({"&:hover": {"color": "hotpink"}})}, ), ( {}, {"_hover": {"color": "red"}}, {"css": Var.create({"&:hover": {"color": "red"}})}, ), ( {}, {":hover": {"color": "red"}}, {"css": Var.create({"&:hover": {"color": "red"}})}, ), ( {}, {"::-webkit-scrollbar": {"display": "none"}}, {"css": Var.create({"&::-webkit-scrollbar": {"display": "none"}})}, ), ( {}, {"::-moz-progress-bar": {"background_color": "red"}}, {"css": Var.create({"&::-moz-progress-bar": {"backgroundColor": "red"}})}, ), ( {"color": ["#111", "#222", "#333", "#444", "#555"]}, {}, { "css": Var.create( { "@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": Var.create( { "@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": Var.create( { "@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": Var.create( { "&: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": Var.create( { "&: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": Var.create( { "&: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": Var.create( { "&: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": Var.create({"color": StyleState.color})}, ), ( {"color": f"dark{StyleState.color}"}, {"css": Var.create_safe(f'{{"color": `dark{StyleState.color}`}}').to(dict)}, ), ( {"color": StyleState.color, "_hover": {"color": StyleState.color2}}, { "css": Var.create( { "color": StyleState.color, "&:hover": {"color": StyleState.color2}, } ) }, ), ( {"color": [StyleState.color, "gray", StyleState.color2, "yellow", "blue"]}, { "css": Var.create( { "@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": Var.create( { "&: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": Var.create( { "&: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 comp.style._var_data == expected_get_style["css"]._var_data # Remove the _var_data from the expected style, since the emotion-formatted # style dict won't actually have it. expected_get_style["css"]._var_data = None # Assert that style values are equal. compare_dict_of_var(comp._get_style(), expected_get_style)