From 24363170d33bb2b4d4fc5041a38bf0b42085e234 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 30 Oct 2024 11:31:28 -0700 Subject: [PATCH] components as literal vars (#4223) * component as literal vars * fix pyi * use render * fix pyi * only render once * add type ignore * fix upload default value * remove testcases if you don't pass them * improve behavior * fix render * that's not how icon buttons work * upgrade to next js 15 and remove babel and enable turbo * upload is a silly guy * woops * how did this work before * set env variable * lower it even more * lower it even more * lower it even more * only do literals as component vars --- .../jinja/web/pages/utils.js.jinja2 | 12 +- reflex/.templates/web/utils/state.js | 4 +- reflex/components/base/bare.py | 75 ++++++- reflex/components/component.py | 211 +++++++++++++++++- reflex/components/core/upload.py | 102 +++++++-- reflex/components/core/upload.pyi | 6 +- reflex/components/dynamic.py | 8 +- reflex/components/tags/tag.py | 5 +- tests/integration/test_form_submit.py | 2 +- tests/integration/test_var_operations.py | 4 +- tests/units/components/forms/test_uploads.py | 205 ----------------- tests/units/components/test_component.py | 19 +- 12 files changed, 383 insertions(+), 270 deletions(-) delete mode 100644 tests/units/components/forms/test_uploads.py diff --git a/reflex/.templates/jinja/web/pages/utils.js.jinja2 b/reflex/.templates/jinja/web/pages/utils.js.jinja2 index 908482d24..624e3bee8 100644 --- a/reflex/.templates/jinja/web/pages/utils.js.jinja2 +++ b/reflex/.templates/jinja/web/pages/utils.js.jinja2 @@ -36,14 +36,10 @@ {# component: component dictionary #} {% macro render_tag(component) %} <{{component.name}} {{- render_props(component.props) }}> -{%- if component.args is not none -%} - {{- render_arg_content(component) }} -{%- else -%} - {{ component.contents }} - {% for child in component.children %} - {{ render(child) }} - {% endfor %} -{%- endif -%} +{{ component.contents }} +{% for child in component.children %} +{{ render(child) }} +{% endfor %} {%- endmacro %} diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index e577df67d..7d76b080a 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -15,7 +15,6 @@ import { } from "$/utils/context.js"; import debounce from "$/utils/helpers/debounce"; import throttle from "$/utils/helpers/throttle"; -import * as Babel from "@babel/standalone"; // Endpoint URLs. const EVENTURL = env.EVENT; @@ -139,8 +138,7 @@ export const evalReactComponent = async (component) => { if (!window.React && window.__reflex) { window.React = window.__reflex.react; } - const output = Babel.transform(component, { presets: ["react"] }).code; - const encodedJs = encodeURIComponent(output); + const encodedJs = encodeURIComponent(component); const dataUri = "data:text/javascript;charset=utf-8," + encodedJs; const module = await eval(`import(dataUri)`); return module.default; diff --git a/reflex/components/base/bare.py b/reflex/components/base/bare.py index ada511ef2..c70b4c844 100644 --- a/reflex/components/base/bare.py +++ b/reflex/components/base/bare.py @@ -4,10 +4,11 @@ from __future__ import annotations from typing import Any, Iterator -from reflex.components.component import Component +from reflex.components.component import Component, LiteralComponentVar from reflex.components.tags import Tag from reflex.components.tags.tagless import Tagless -from reflex.vars import ArrayVar, BooleanVar, ObjectVar, Var +from reflex.utils.imports import ParsedImportDict +from reflex.vars import BooleanVar, ObjectVar, Var class Bare(Component): @@ -31,9 +32,77 @@ class Bare(Component): contents = str(contents) if contents is not None else "" return cls(contents=contents) # type: ignore + def _get_all_hooks_internal(self) -> dict[str, None]: + """Include the hooks for the component. + + Returns: + The hooks for the component. + """ + hooks = super()._get_all_hooks_internal() + if isinstance(self.contents, LiteralComponentVar): + hooks |= self.contents._var_value._get_all_hooks_internal() + return hooks + + def _get_all_hooks(self) -> dict[str, None]: + """Include the hooks for the component. + + Returns: + The hooks for the component. + """ + hooks = super()._get_all_hooks() + if isinstance(self.contents, LiteralComponentVar): + hooks |= self.contents._var_value._get_all_hooks() + return hooks + + def _get_all_imports(self) -> ParsedImportDict: + """Include the imports for the component. + + Returns: + The imports for the component. + """ + imports = super()._get_all_imports() + if isinstance(self.contents, LiteralComponentVar): + var_data = self.contents._get_all_var_data() + if var_data: + imports |= {k: list(v) for k, v in var_data.imports} + return imports + + def _get_all_dynamic_imports(self) -> set[str]: + """Get dynamic imports for the component. + + Returns: + The dynamic imports. + """ + dynamic_imports = super()._get_all_dynamic_imports() + if isinstance(self.contents, LiteralComponentVar): + dynamic_imports |= self.contents._var_value._get_all_dynamic_imports() + return dynamic_imports + + def _get_all_custom_code(self) -> set[str]: + """Get custom code for the component. + + Returns: + The custom code. + """ + custom_code = super()._get_all_custom_code() + if isinstance(self.contents, LiteralComponentVar): + custom_code |= self.contents._var_value._get_all_custom_code() + return custom_code + + def _get_all_refs(self) -> set[str]: + """Get the refs for the children of the component. + + Returns: + The refs for the children. + """ + refs = super()._get_all_refs() + if isinstance(self.contents, LiteralComponentVar): + refs |= self.contents._var_value._get_all_refs() + return refs + def _render(self) -> Tag: if isinstance(self.contents, Var): - if isinstance(self.contents, (BooleanVar, ObjectVar, ArrayVar)): + if isinstance(self.contents, (BooleanVar, ObjectVar)): return Tagless(contents=f"{{{str(self.contents.to_string())}}}") return Tagless(contents=f"{{{str(self.contents)}}}") return Tagless(contents=str(self.contents)) diff --git a/reflex/components/component.py b/reflex/components/component.py index 5c6234749..399becee9 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -3,6 +3,7 @@ from __future__ import annotations import copy +import dataclasses import typing from abc import ABC, abstractmethod from functools import lru_cache, wraps @@ -59,7 +60,15 @@ from reflex.utils.imports import ( parse_imports, ) from reflex.vars import VarData -from reflex.vars.base import LiteralVar, Var +from reflex.vars.base import ( + CachedVarOperation, + LiteralVar, + Var, + cached_property_no_lock, +) +from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar +from reflex.vars.number import ternary_operation +from reflex.vars.object import ObjectVar from reflex.vars.sequence import LiteralArrayVar @@ -2345,3 +2354,203 @@ class MemoizationLeaf(Component): load_dynamic_serializer() + + +class ComponentVar(Var[Component], python_types=BaseComponent): + """A Var that represents a Component.""" + + +def empty_component() -> Component: + """Create an empty component. + + Returns: + An empty component. + """ + from reflex.components.base.bare import Bare + + return Bare.create("") + + +def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) -> Var: + """Convert a render dict to a Var. + + Args: + tag: The render dict. + imported_names: The names of the imported components. + + Returns: + The Var. + """ + if not isinstance(tag, dict): + if isinstance(tag, Component): + return render_dict_to_var(tag.render(), imported_names) + return Var.create(tag) + + if "iterable" in tag: + function_return = Var.create( + [ + render_dict_to_var(child.render(), imported_names) + for child in tag["children"] + ] + ) + + func = ArgsFunctionOperation.create( + (tag["arg_var_name"], tag["index_var_name"]), + function_return, + ) + + return FunctionStringVar.create("Array.prototype.map.call").call( + tag["iterable"] + if not isinstance(tag["iterable"], ObjectVar) + else tag["iterable"].items(), + func, + ) + + if tag["name"] == "match": + element = tag["cond"] + + conditionals = tag["default"] + + for case in tag["match_cases"][::-1]: + condition = case[0].to_string() == element.to_string() + for pattern in case[1:-1]: + condition = condition | (pattern.to_string() == element.to_string()) + + conditionals = ternary_operation( + condition, + case[-1], + conditionals, + ) + + return conditionals + + if "cond" in tag: + return ternary_operation( + tag["cond"], + render_dict_to_var(tag["true_value"], imported_names), + render_dict_to_var(tag["false_value"], imported_names) + if tag["false_value"] is not None + else Var.create(None), + ) + + props = {} + + special_props = [] + + for prop_str in tag["props"]: + if "=" not in prop_str: + special_props.append(Var(prop_str).to(ObjectVar)) + continue + prop = prop_str.index("=") + key = prop_str[:prop] + value = prop_str[prop + 2 : -1] + props[key] = value + + props = Var.create({Var.create(k): Var(v) for k, v in props.items()}) + + for prop in special_props: + props = props.merge(prop) + + contents = tag["contents"][1:-1] if tag["contents"] else None + + raw_tag_name = tag.get("name") + tag_name = Var(raw_tag_name or "Fragment") + + tag_name = ( + Var.create(raw_tag_name) + if raw_tag_name + and raw_tag_name.split(".")[0] not in imported_names + and raw_tag_name.lower() == raw_tag_name + else tag_name + ) + + return FunctionStringVar.create( + "jsx", + ).call( + tag_name, + props, + *([Var(contents)] if contents is not None else []), + *[render_dict_to_var(child, imported_names) for child in tag["children"]], + ) + + +@dataclasses.dataclass( + eq=False, + frozen=True, +) +class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar): + """A Var that represents a Component.""" + + _var_value: BaseComponent = dataclasses.field(default_factory=empty_component) + + @cached_property_no_lock + def _cached_var_name(self) -> str: + """Get the name of the var. + + Returns: + The name of the var. + """ + var_data = self._get_all_var_data() + if var_data is not None: + # flatten imports + imported_names = {j.alias or j.name for i in var_data.imports for j in i[1]} + else: + imported_names = set() + return str(render_dict_to_var(self._var_value.render(), imported_names)) + + @cached_property_no_lock + def _cached_get_all_var_data(self) -> VarData | None: + """Get the VarData for the var. + + Returns: + The VarData for the var. + """ + return VarData.merge( + VarData( + imports={ + "@emotion/react": [ + ImportVar(tag="jsx"), + ], + } + ), + VarData( + imports=self._var_value._get_all_imports(), + ), + VarData( + imports={ + "react": [ + ImportVar(tag="Fragment"), + ], + } + ), + ) + + def __hash__(self) -> int: + """Get the hash of the var. + + Returns: + The hash of the var. + """ + return hash((self.__class__.__name__, self._js_expr)) + + @classmethod + def create( + cls, + value: Component, + _var_data: VarData | None = None, + ): + """Create a var from a value. + + Args: + value: The value of the var. + _var_data: Additional hooks and imports associated with the Var. + + Returns: + The var. + """ + return LiteralComponentVar( + _js_expr="", + _var_type=type(value), + _var_data=_var_data, + _var_value=value, + ) diff --git a/reflex/components/core/upload.py b/reflex/components/core/upload.py index c454cba7d..787cca9d0 100644 --- a/reflex/components/core/upload.py +++ b/reflex/components/core/upload.py @@ -5,11 +5,17 @@ from __future__ import annotations from pathlib import Path from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple -from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf +from reflex.components.component import ( + Component, + ComponentNamespace, + MemoizationLeaf, + StatefulComponent, +) from reflex.components.el.elements.forms import Input from reflex.components.radix.themes.layout.box import Box from reflex.config import environment from reflex.constants import Dirs +from reflex.constants.compiler import Imports from reflex.event import ( CallableEventSpec, EventChain, @@ -19,9 +25,10 @@ from reflex.event import ( call_script, parse_args_spec, ) +from reflex.utils import format from reflex.utils.imports import ImportVar from reflex.vars import VarData -from reflex.vars.base import CallableVar, LiteralVar, Var +from reflex.vars.base import CallableVar, LiteralVar, Var, get_unique_variable_name from reflex.vars.sequence import LiteralStringVar DEFAULT_UPLOAD_ID: str = "default" @@ -179,9 +186,7 @@ class Upload(MemoizationLeaf): library = "react-dropzone@14.2.10" - tag = "ReactDropzone" - - is_default = True + tag = "" # The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as # values. @@ -201,7 +206,7 @@ class Upload(MemoizationLeaf): min_size: Var[int] # Whether to allow multiple files to be uploaded. - multiple: Var[bool] = True # type: ignore + multiple: Var[bool] # Whether to disable click to upload. no_click: Var[bool] @@ -232,6 +237,8 @@ class Upload(MemoizationLeaf): # Mark the Upload component as used in the app. cls.is_used = True + props.setdefault("multiple", True) + # Apply the default classname given_class_name = props.pop("class_name", []) if isinstance(given_class_name, str): @@ -243,17 +250,6 @@ class Upload(MemoizationLeaf): upload_props = { key: value for key, value in props.items() if key in supported_props } - # The file input to use. - upload = Input.create(type="file") - upload.special_props = [Var(_js_expr="{...getInputProps()}", _var_type=None)] - - # The dropzone to use. - zone = Box.create( - upload, - *children, - **{k: v for k, v in props.items() if k not in supported_props}, - ) - zone.special_props = [Var(_js_expr="{...getRootProps()}", _var_type=None)] # Create the component. upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID) @@ -275,9 +271,74 @@ class Upload(MemoizationLeaf): ), ) upload_props["on_drop"] = on_drop + + input_props_unique_name = get_unique_variable_name() + root_props_unique_name = get_unique_variable_name() + + event_var, callback_str = StatefulComponent._get_memoized_event_triggers( + Box.create(on_click=upload_props["on_drop"]) # type: ignore + )["on_click"] + + upload_props["on_drop"] = event_var + + upload_props = { + format.to_camel_case(key): value for key, value in upload_props.items() + } + + use_dropzone_arguements = { + "onDrop": event_var, + **upload_props, + } + + left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} " + right_side = f"useDropzone({str(Var.create(use_dropzone_arguements))})" + + var_data = VarData.merge( + VarData( + imports=Imports.EVENTS, + hooks={ + "const [addEvents, connectError] = useContext(EventLoopContext);": None + }, + ), + event_var._get_all_var_data(), + VarData( + hooks={ + callback_str: None, + f"{left_side} = {right_side};": None, + }, + imports={ + "react-dropzone": "useDropzone", + **Imports.EVENTS, + }, + ), + ) + + # The file input to use. + upload = Input.create(type="file") + upload.special_props = [ + Var( + _js_expr=f"{{...{input_props_unique_name}()}}", + _var_type=None, + _var_data=var_data, + ) + ] + + # The dropzone to use. + zone = Box.create( + upload, + *children, + **{k: v for k, v in props.items() if k not in supported_props}, + ) + zone.special_props = [ + Var( + _js_expr=f"{{...{root_props_unique_name}()}}", + _var_type=None, + _var_data=var_data, + ) + ] + return super().create( zone, - **upload_props, ) @classmethod @@ -295,11 +356,6 @@ class Upload(MemoizationLeaf): return (arg_value[0], placeholder) return arg_value - def _render(self): - out = super()._render() - out.args = ("getRootProps", "getInputProps") - return out - @staticmethod def _get_app_wrap_components() -> dict[tuple[int, str], Component]: return { diff --git a/reflex/components/core/upload.pyi b/reflex/components/core/upload.pyi index 43ce3b63d..e5c73bd14 100644 --- a/reflex/components/core/upload.pyi +++ b/reflex/components/core/upload.pyi @@ -6,7 +6,11 @@ from pathlib import Path from typing import Any, ClassVar, Dict, List, Optional, Union, overload -from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf +from reflex.components.component import ( + Component, + ComponentNamespace, + MemoizationLeaf, +) from reflex.constants import Dirs from reflex.event import ( CallableEventSpec, diff --git a/reflex/components/dynamic.py b/reflex/components/dynamic.py index e391c9fd0..c0e172224 100644 --- a/reflex/components/dynamic.py +++ b/reflex/components/dynamic.py @@ -63,6 +63,9 @@ def load_dynamic_serializer(): """ # Causes a circular import, so we import here. from reflex.compiler import templates, utils + from reflex.components.base.bare import Bare + + component = Bare.create(Var.create(component)) rendered_components = {} # Include dynamic imports in the shared component. @@ -127,14 +130,15 @@ def load_dynamic_serializer(): module_code_lines[ix] = line.replace( "export function", "export default function", 1 ) + line_stripped = line.strip() + if line_stripped.startswith("{") and line_stripped.endswith("}"): + module_code_lines[ix] = line_stripped[1:-1] module_code_lines.insert(0, "const React = window.__reflex.react;") return "\n".join( [ "//__reflex_evaluate", - "/** @jsx jsx */", - "const { jsx } = window.__reflex['@emotion/react']", *module_code_lines, ] ) diff --git a/reflex/components/tags/tag.py b/reflex/components/tags/tag.py index d577abc6e..0587c61ed 100644 --- a/reflex/components/tags/tag.py +++ b/reflex/components/tags/tag.py @@ -3,7 +3,7 @@ from __future__ import annotations import dataclasses -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Union from reflex.event import EventChain from reflex.utils import format, types @@ -23,9 +23,6 @@ class Tag: # The inner contents of the tag. contents: str = "" - # Args to pass to the tag. - args: Optional[Tuple[str, ...]] = None - # Special props that aren't key value pairs. special_props: List[Var] = dataclasses.field(default_factory=list) diff --git a/tests/integration/test_form_submit.py b/tests/integration/test_form_submit.py index a020a7e15..3bfcf6e8c 100644 --- a/tests/integration/test_form_submit.py +++ b/tests/integration/test_form_submit.py @@ -121,7 +121,7 @@ def FormSubmitName(form_component): on_change=rx.console_log, ), rx.button("Submit", type_="submit"), - rx.icon_button(FormState.val, icon=rx.icon(tag="plus")), + rx.icon_button(rx.icon(tag="plus")), ), on_submit=FormState.form_submit, custom_attrs={"action": "/invalid"}, diff --git a/tests/integration/test_var_operations.py b/tests/integration/test_var_operations.py index 919a39f3b..cae56e1a8 100644 --- a/tests/integration/test_var_operations.py +++ b/tests/integration/test_var_operations.py @@ -793,8 +793,8 @@ def test_var_operations(driver, var_operations: AppHarness): ("foreach_list_ix", "1\n2"), ("foreach_list_nested", "1\n1\n2"), # rx.memo component with state - ("memo_comp", "[1,2]10"), - ("memo_comp_nested", "[3,4]5"), + ("memo_comp", "1210"), + ("memo_comp_nested", "345"), # foreach in a match ("foreach_in_match", "first\nsecond\nthird"), ] diff --git a/tests/units/components/forms/test_uploads.py b/tests/units/components/forms/test_uploads.py deleted file mode 100644 index 3b2ee014f..000000000 --- a/tests/units/components/forms/test_uploads.py +++ /dev/null @@ -1,205 +0,0 @@ -import pytest - -import reflex as rx - - -@pytest.fixture -def upload_root_component(): - """A test upload component function. - - Returns: - A test upload component function. - """ - - def upload_root_component(): - return rx.upload.root( - rx.button("select file"), - rx.text("Drag and drop files here or click to select files"), - border="1px dotted black", - ) - - return upload_root_component() - - -@pytest.fixture -def upload_component(): - """A test upload component function. - - Returns: - A test upload component function. - """ - - def upload_component(): - return rx.upload( - rx.button("select file"), - rx.text("Drag and drop files here or click to select files"), - border="1px dotted black", - ) - - return upload_component() - - -@pytest.fixture -def upload_component_id_special(): - def upload_component(): - return rx.upload( - rx.button("select file"), - rx.text("Drag and drop files here or click to select files"), - border="1px dotted black", - id="#spec!`al-_98ID", - ) - - return upload_component() - - -@pytest.fixture -def upload_component_with_props(): - """A test upload component with props function. - - Returns: - A test upload component with props function. - """ - - def upload_component_with_props(): - return rx.upload( - rx.button("select file"), - rx.text("Drag and drop files here or click to select files"), - border="1px dotted black", - no_drag=True, - max_files=2, - ) - - return upload_component_with_props() - - -def test_upload_root_component_render(upload_root_component): - """Test that the render function is set correctly. - - Args: - upload_root_component: component fixture - """ - upload = upload_root_component.render() - - # upload - assert upload["name"] == "ReactDropzone" - assert upload["props"] == [ - 'id={"default"}', - "multiple={true}", - "onDrop={e => setFilesById(filesById => {\n" - " const updatedFilesById = Object.assign({}, filesById);\n" - ' updatedFilesById["default"] = e;\n' - " return updatedFilesById;\n" - " })\n" - " }", - "ref={ref_default}", - ] - assert upload["args"] == ("getRootProps", "getInputProps") - - # box inside of upload - [box] = upload["children"] - assert box["name"] == "RadixThemesBox" - assert box["props"] == [ - 'className={"rx-Upload"}', - 'css={({ ["border"] : "1px dotted black" })}', - "{...getRootProps()}", - ] - - # input, button and text inside of box - [input, button, text] = box["children"] - assert input["name"] == "input" - assert input["props"] == ['type={"file"}', "{...getInputProps()}"] - - assert button["name"] == "RadixThemesButton" - assert button["children"][0]["contents"] == '{"select file"}' - - assert text["name"] == "RadixThemesText" - assert ( - text["children"][0]["contents"] - == '{"Drag and drop files here or click to select files"}' - ) - - -def test_upload_component_render(upload_component): - """Test that the render function is set correctly. - - Args: - upload_component: component fixture - """ - upload = upload_component.render() - - # upload - assert upload["name"] == "ReactDropzone" - assert upload["props"] == [ - 'id={"default"}', - "multiple={true}", - "onDrop={e => setFilesById(filesById => {\n" - " const updatedFilesById = Object.assign({}, filesById);\n" - ' updatedFilesById["default"] = e;\n' - " return updatedFilesById;\n" - " })\n" - " }", - "ref={ref_default}", - ] - assert upload["args"] == ("getRootProps", "getInputProps") - - # box inside of upload - [box] = upload["children"] - assert box["name"] == "RadixThemesBox" - assert box["props"] == [ - 'className={"rx-Upload"}', - 'css={({ ["border"] : "1px dotted black", ["padding"] : "5em", ["textAlign"] : "center" })}', - "{...getRootProps()}", - ] - - # input, button and text inside of box - [input, button, text] = box["children"] - assert input["name"] == "input" - assert input["props"] == ['type={"file"}', "{...getInputProps()}"] - - assert button["name"] == "RadixThemesButton" - assert button["children"][0]["contents"] == '{"select file"}' - - assert text["name"] == "RadixThemesText" - assert ( - text["children"][0]["contents"] - == '{"Drag and drop files here or click to select files"}' - ) - - -def test_upload_component_with_props_render(upload_component_with_props): - """Test that the render function is set correctly. - - Args: - upload_component_with_props: component fixture - """ - upload = upload_component_with_props.render() - - assert upload["props"] == [ - 'id={"default"}', - "maxFiles={2}", - "multiple={true}", - "noDrag={true}", - "onDrop={e => setFilesById(filesById => {\n" - " const updatedFilesById = Object.assign({}, filesById);\n" - ' updatedFilesById["default"] = e;\n' - " return updatedFilesById;\n" - " })\n" - " }", - "ref={ref_default}", - ] - - -def test_upload_component_id_with_special_chars(upload_component_id_special): - upload = upload_component_id_special.render() - - assert upload["props"] == [ - r'id={"#spec!`al-_98ID"}', - "multiple={true}", - "onDrop={e => setFilesById(filesById => {\n" - " const updatedFilesById = Object.assign({}, filesById);\n" - ' updatedFilesById["#spec!`al-_98ID"] = e;\n' - " return updatedFilesById;\n" - " })\n" - " }", - "ref={ref__spec_al__98ID}", - ] diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index b7b721a92..c2d73aca5 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -642,21 +642,18 @@ def test_component_create_unallowed_types(children, test_component): "name": "Fragment", "props": [], "contents": "", - "args": None, "special_props": [], "children": [ { "name": "RadixThemesText", "props": ['as={"p"}'], "contents": "", - "args": None, "special_props": [], "children": [ { "name": "", "props": [], "contents": '{"first_text"}', - "args": None, "special_props": [], "children": [], "autofocus": False, @@ -671,15 +668,12 @@ def test_component_create_unallowed_types(children, test_component): ( (rx.text("first_text"), rx.text("second_text")), { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [], "contents": '{"first_text"}', @@ -694,11 +688,9 @@ def test_component_create_unallowed_types(children, test_component): "special_props": [], }, { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [], "contents": '{"second_text"}', @@ -722,15 +714,12 @@ def test_component_create_unallowed_types(children, test_component): ( (rx.text("first_text"), rx.box((rx.text("second_text"),))), { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [], "contents": '{"first_text"}', @@ -745,19 +734,15 @@ def test_component_create_unallowed_types(children, test_component): "special_props": [], }, { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [ { - "args": None, "autofocus": False, "children": [], "contents": '{"second_text"}', @@ -1117,10 +1102,10 @@ def test_component_with_only_valid_children(fixture, request): @pytest.mark.parametrize( "component,rendered", [ - (rx.text("hi"), '\n {"hi"}\n'), + (rx.text("hi"), '\n\n{"hi"}\n'), ( rx.box(rx.heading("test", size="3")), - '\n \n {"test"}\n\n', + '\n\n\n\n{"test"}\n\n', ), ], )