Example #1
0
async def test_duplicate_sibling_keys_causes_error(caplog):
    hook = HookCatcher()
    should_error = True

    @idom.component
    @hook.capture
    def ComponentReturnsDuplicateKeys():
        if should_error:
            return idom.html.div(
                idom.html.div(key="duplicate"),
                idom.html.div(key="duplicate"),
            )
        else:
            return idom.html.div()

    async with idom.Layout(ComponentReturnsDuplicateKeys()) as layout:
        with assert_idom_did_log(
                error_type=ValueError,
                match_error=r"Duplicate keys \['duplicate'\] at '/children/0'",
        ):
            await layout.render()

        hook.latest.schedule_render()

        should_error = False
        await layout.render()

        should_error = True
        hook.latest.schedule_render()
        with assert_idom_did_log(
                error_type=ValueError,
                match_error=r"Duplicate keys \['duplicate'\] at '/children/0'",
        ):
            await layout.render()
Example #2
0
async def test_use_debug_mode_with_factory():
    set_message = idom.Ref()
    component_hook = HookCatcher()

    @idom.component
    @component_hook.capture
    def SomeComponent():
        message, set_message.current = idom.use_state("hello")
        idom.use_debug_value(lambda: f"message is {message!r}")
        return idom.html.div()

    async with idom.Layout(SomeComponent()) as layout:

        with assert_idom_did_log(r"SomeComponent\(.*?\) message is 'hello'"):
            await layout.render()

        set_message.current("bye")

        with assert_idom_did_log(r"SomeComponent\(.*?\) message is 'bye'"):
            await layout.render()

        component_hook.latest.schedule_render()

        with assert_idom_did_not_log(r"SomeComponent\(.*?\) message is 'bye'"):
            await layout.render()
Example #3
0
def test_assert_idom_logged_error():
    with testing.assert_idom_did_log(
            match_message="log message",
            error_type=ValueError,
            match_error="my value error",
    ):
        try:
            raise ValueError("my value error")
        except ValueError:
            ROOT_LOGGER.exception("log message")

    with pytest.raises(
            AssertionError,
            match=r"Could not find a log record matching the given",
    ):
        with testing.assert_idom_did_log(
                match_message="log message",
                error_type=ValueError,
                match_error="my value error",
        ):
            try:
                # change error type
                raise RuntimeError("my value error")
            except RuntimeError:
                ROOT_LOGGER.exception("log message")

    with pytest.raises(
            AssertionError,
            match=r"Could not find a log record matching the given",
    ):
        with testing.assert_idom_did_log(
                match_message="log message",
                error_type=ValueError,
                match_error="my value error",
        ):
            try:
                # change error message
                raise ValueError("something else")
            except ValueError:
                ROOT_LOGGER.exception("log message")

    with pytest.raises(
            AssertionError,
            match=r"Could not find a log record matching the given",
    ):
        with testing.assert_idom_did_log(
                match_message="log message",
                error_type=ValueError,
                match_error="my value error",
        ):
            try:
                # change error message
                raise ValueError("my error message")
            except ValueError:
                ROOT_LOGGER.exception("something else")
Example #4
0
async def test_layout_render_error_has_partial_update_with_error_message():
    @idom.component
    def Main():
        return idom.html.div([OkChild(), BadChild(), OkChild()])

    @idom.component
    def OkChild():
        return idom.html.div(["hello"])

    @idom.component
    def BadChild():
        raise ValueError("error from bad child")

    with assert_idom_did_log(match_error="error from bad child"):

        async with idom.Layout(Main()) as layout:
            patch = await render_json_patch(layout)
            assert_same_items(
                patch.changes,
                [
                    {
                        "op":
                        "add",
                        "path":
                        "/children",
                        "value": [{
                            "tagName":
                            "div",
                            "children": [
                                {
                                    "tagName":
                                    "",
                                    "children": [{
                                        "tagName": "div",
                                        "children": ["hello"]
                                    }],
                                },
                                {
                                    "tagName": "",
                                    "error":
                                    "ValueError: error from bad child",
                                },
                                {
                                    "tagName":
                                    "",
                                    "children": [{
                                        "tagName": "div",
                                        "children": ["hello"]
                                    }],
                                },
                            ],
                        }],
                    },
                    {
                        "op": "add",
                        "path": "/tagName",
                        "value": ""
                    },
                ],
            )
Example #5
0
def test_bad_schedule_render_callback():
    def bad_callback():
        raise ValueError("something went wrong")

    with assert_idom_did_log(
            match_message=f"Failed to schedule render via {bad_callback}"):
        LifeCycleHook(bad_callback).schedule_render()
Example #6
0
async def test_error_in_effect_pre_unmount_cleanup_is_gracefully_handled():
    set_key = idom.Ref()

    @idom.component
    def OuterComponent():
        key, set_key.current = idom.use_state("first")
        return ComponentWithEffect(key=key)

    @idom.component
    def ComponentWithEffect():
        @idom.hooks.use_effect
        def ok_effect():
            def bad_cleanup():
                raise ValueError("Something went wong :(")

            return bad_cleanup

        return idom.html.div()

    with assert_idom_did_log(
            match_message=r"Pre-unmount effect .*? failed",
            error_type=ValueError,
    ):
        async with idom.Layout(OuterComponent()) as layout:
            await layout.render()
            set_key.current("second")
            await layout.render()  # no error
Example #7
0
def test_assert_idom_logged_ignores_level():
    original_level = ROOT_LOGGER.level
    ROOT_LOGGER.setLevel(logging.INFO)
    try:
        with testing.assert_idom_did_log(match_message=r".*"):
            # this log would normally be ignored
            ROOT_LOGGER.debug("my message")
    finally:
        ROOT_LOGGER.setLevel(original_level)
Example #8
0
def test_web_module_from_file_replace_existing(tmp_path):
    file1 = tmp_path / "temp1.js"
    file1.touch()

    idom.web.module_from_file("temp", file1)

    file2 = tmp_path / "temp2.js"
    file2.write_text("something")

    with assert_idom_did_log(r"Existing web module .* will be replaced with"):
        idom.web.module_from_file("temp", file2)
Example #9
0
def test_assert_idom_logged_assertion_error_message():
    with pytest.raises(
            AssertionError,
            match=r"Could not find a log record matching the given",
    ):
        with testing.assert_idom_did_log(
                # put in all possible params full assertion error message
                match_message=r".*",
                error_type=Exception,
                match_error=r".*",
        ):
            pass
Example #10
0
async def test_error_in_effect_is_gracefully_handled(caplog):
    @idom.component
    def ComponentWithEffect():
        @idom.hooks.use_effect
        def bad_effect():
            raise ValueError("Something went wong :(")

        return idom.html.div()

    with assert_idom_did_log(
            match_message=r"Layout post-render effect .* failed"):
        async with idom.Layout(ComponentWithEffect()) as layout:
            await layout.render()  # no error
Example #11
0
def test_web_module_from_file_symlink_twice(tmp_path):
    file_1 = tmp_path / "temp_1.js"
    file_1.touch()

    idom.web.module_from_file("temp", file_1, symlink=True)

    with assert_idom_did_not_log(
            r"Existing web module .* will be replaced with"):
        idom.web.module_from_file("temp", file_1, symlink=True)

    file_2 = tmp_path / "temp_2.js"
    file_2.write_text("something")

    with assert_idom_did_log(r"Existing web module .* will be replaced with"):
        idom.web.module_from_file("temp", file_2, symlink=True)
Example #12
0
async def test_log_error_on_bad_event_handler():
    bad_handler = StaticEventHandler()

    @idom.component
    def ComponentWithBadEventHandler():
        @bad_handler.use
        def raise_error():
            raise Exception("bad event handler")

        return idom.html.button({"onClick": raise_error})

    with assert_idom_did_log(match_error="bad event handler"):

        async with idom.Layout(ComponentWithBadEventHandler()) as layout:
            await layout.render()
            event = LayoutEvent(bad_handler.target, [])
            await layout.deliver(event)
Example #13
0
def test_module_from_file_source_conflict(tmp_path):
    first_file = tmp_path / "first.js"

    with pytest.raises(FileNotFoundError, match="does not exist"):
        idom.web.module_from_file("temp", first_file)

    first_file.touch()

    idom.web.module_from_file("temp", first_file)

    second_file = tmp_path / "second.js"
    second_file.touch()

    # ok, same content
    idom.web.module_from_file("temp", second_file)

    third_file = tmp_path / "third.js"
    third_file.write_text("something-different")

    with assert_idom_did_log(r"Existing web module .* will be replaced with"):
        idom.web.module_from_file("temp", third_file)
Example #14
0
async def test_component_error_in_should_render_is_handled_gracefully():
    root_hook = HookCatcher()

    @idom.component
    @root_hook.capture
    def Root():
        def bad_should_render(new):
            raise ValueError("The error message")

        return ComponentShouldRender(html.div(),
                                     should_render=bad_should_render)

    with assert_idom_did_log(
            match_message=
            r".* component failed to check if .* should be rendered",
            error_type=ValueError,
            match_error="The error message",
    ):
        async with idom.Layout(Root()) as layout:
            await layout.render()
            root_hook.latest.schedule_render()
            await layout.render()
Example #15
0
async def test_error_in_effect_cleanup_is_gracefully_handled(caplog):
    caplog.clear()
    component_hook = HookCatcher()

    @idom.component
    @component_hook.capture
    def ComponentWithEffect():
        @idom.hooks.use_effect(dependencies=None
                               )  # force this to run every time
        def ok_effect():
            def bad_cleanup():
                raise ValueError("Something went wong :(")

            return bad_cleanup

        return idom.html.div()

    with assert_idom_did_log(
            match_error=r"Layout post-render effect .* failed"):
        async with idom.Layout(ComponentWithEffect()) as layout:
            await layout.render()
            component_hook.latest.schedule_render()
            await layout.render()  # no error
Example #16
0
async def test_error_in_effect_cleanup_is_gracefully_handled():
    component_hook = HookCatcher()

    @idom.component
    @component_hook.capture
    def ComponentWithEffect():
        hook = current_hook()

        def bad_effect():
            raise ValueError("The error message")

        hook.add_effect(COMPONENT_DID_RENDER_EFFECT, bad_effect)
        return idom.html.div()

    with assert_idom_did_log(
            match_message="Component post-render effect .*? failed",
            error_type=ValueError,
            match_error="The error message",
    ):
        async with idom.Layout(ComponentWithEffect()) as layout:
            await layout.render()
            component_hook.latest.schedule_render()
            await layout.render()  # no error
Example #17
0
async def test_schedule_render_from_unmounted_hook():
    parent_set_state = idom.Ref()

    @idom.component
    def Parent():
        state, parent_set_state.current = idom.hooks.use_state(1)
        return Child(key=state, state=state)

    child_hook = HookCatcher()

    @idom.component
    @child_hook.capture
    def Child(state):
        idom.hooks.use_effect(lambda: lambda: print("unmount", state))
        return idom.html.div(state)

    with assert_idom_did_log(
            r"Did not render component with model state ID .*? - component already unmounted",
    ):
        async with idom.Layout(Parent()) as layout:
            await layout.render()

            old_hook = child_hook.latest

            # cause initial child to be unmounted
            parent_set_state.current(2)
            await layout.render()

            # trigger render for hook that's been unmounted
            old_hook.schedule_render()

            # schedule one more render just to make it so `layout.render()` doesn't hang
            # when the scheduled render above gets skipped
            parent_set_state.current(3)

            await layout.render()
Example #18
0
def test_module_from_string():
    idom.web.module_from_string("temp", "old")
    with assert_idom_did_log(r"Existing web module .* will be replaced with"):
        idom.web.module_from_string("temp", "new")
Example #19
0
def test_assert_idom_logged_does_not_supress_errors():
    with pytest.raises(RuntimeError, match="expected error"):
        with testing.assert_idom_did_log():
            raise RuntimeError("expected error")
Example #20
0
def test_log_on_unknown_export_type():
    with assert_idom_did_log(match_message="Unknown export type "):
        assert resolve_module_exports_from_source(
            "export something unknown;",
            exclude_default=False) == (set(), set())
Example #21
0
def test_assert_idom_logged_message():
    with testing.assert_idom_did_log(match_message="my message"):
        ROOT_LOGGER.info("my message")

    with testing.assert_idom_did_log(match_message=r".*"):
        ROOT_LOGGER.info("my message")