Skip to content

Testing

pythonnative.testing renders components without a device or simulator. render mounts an element into an in-memory FakeBackend and returns a RenderResult with Testing Library-style queries and event helpers; render_hook does the same for a bare hook.

Test utilities: render components without a device.

import pythonnative as pn
from pythonnative.testing import render, render_hook

@pn.component
def Counter():
    count, set_count = pn.use_state(0)
    return pn.Column(
        pn.Text(f"Count: {count}"),
        pn.Button("+", on_press=lambda: set_count(count + 1)),
    )

def test_counter_increments():
    result = render(Counter())
    result.press(result.get_by_text("+"))
    assert result.get_by_text("Count: 1")

def test_use_state():
    hook = render_hook(lambda: pn.use_state("a"))
    hook.act(lambda: hook.current[1]("b"))
    assert hook.current[0] == "b"
  • render mounts an element into a FakeBackend and returns a RenderResult with Testing Library-style queries (get_by_text, get_by_test_id, get_by_label, get_by_type) and event helpers (press, fire, change_text, back).
  • render_hook runs a hook in a throwaway component.
  • settle pumps the framework loop so async work (resources, queries, transitions) completes.
  • FakeHost stands in for a native screen host so root stack navigators can be tested.

Modules:

Name Description
backend

In-memory backend implementing the batched mutation protocol.

harness

Render components into a fake backend and query the result.

Classes:

Name Description
FakeBackend

Tag-table backend recording one tuple per applied mutation.

FakeView

Simulated native view: type, props, children, and last frame.

FakeHost

A HostNavigator that records native screen operations.

HookResult

Handle returned by render_hook.

RenderResult

Handle to a mounted tree: queries, events, re-render, unmount.

Functions:

Name Description
render

Mount element into a FakeBackend.

render_hook

Run hook(*args, **kwargs) inside a throwaway component.

settle

Pump the framework loop and flush pending renders until everything is idle.

Attributes:

Name Type Description
DEFAULT_INTRINSIC Dict[str, Tuple[float, float]]

Intrinsic sizes reported for content-sized leaves (what platform measure hooks would return).

DEFAULT_INTRINSIC module-attribute

DEFAULT_INTRINSIC: Dict[str, Tuple[float, float]] = {
    "Text": (60.0, 16.0),
    "Button": (80.0, 32.0),
    "Image": (40.0, 40.0),
    "TextInput": (120.0, 32.0),
    "TabBar": (320.0, 49.0),
}

Intrinsic sizes reported for content-sized leaves (what platform measure hooks would return).

FakeBackend

FakeBackend(
    intrinsic: Optional[
        Dict[str, Tuple[float, float]]
    ] = None,
)

Tag-table backend recording one tuple per applied mutation.

Parameters:

Name Type Description Default
intrinsic Optional[Dict[str, Tuple[float, float]]]

Override the intrinsic sizes used by measure_intrinsic (defaults to DEFAULT_INTRINSIC).

None

Methods:

Name Description
apply_mutations

Apply one committed batch to the view tree, recording each op in ops and batches.

resolve_view

Return the live view registered under tag, or None.

measure_intrinsic

Return the configured intrinsic size for the view's type and record the call in measure_calls.

command

Record an imperative view command in commands and return None.

set_animated_property

Record an animated property write in animated without touching props.

start_animation

Decline native animation (return False) so animations run through the Python driver.

cancel_animation

Do nothing; the fake never starts native animations.

live_view_count

Return how many views are currently registered (created and not yet destroyed).

ops_of

Every recorded op tuple whose first element is kind.

detached_views

Live views never inserted into a parent (Portal overlays, the root).

apply_mutations

apply_mutations(ops: Sequence[Mutation]) -> None

Apply one committed batch to the view tree, recording each op in ops and batches.

Raises AssertionError on malformed transactions (unknown tags, double creates or destroys).

resolve_view

resolve_view(tag: int) -> Optional[FakeView]

Return the live view registered under tag, or None.

measure_intrinsic

measure_intrinsic(
    tag: int, max_width: float, max_height: float
) -> Tuple[float, float]

Return the configured intrinsic size for the view's type and record the call in measure_calls.

Unknown tags and types without an entry measure as (0.0, 0.0); the constraints are ignored.

command

command(
    tag: int,
    name: str,
    args: Optional[Dict[str, Any]] = None,
) -> Any

Record an imperative view command in commands and return None.

set_animated_property

set_animated_property(
    tag: int, prop_name: str, value: Any
) -> None

Record an animated property write in animated without touching props.

start_animation

start_animation(
    tag: int,
    anim_id: int,
    prop_name: str,
    spec: Dict[str, Any],
) -> bool

Decline native animation (return False) so animations run through the Python driver.

cancel_animation

cancel_animation(tag: int, anim_id: int) -> Any

Do nothing; the fake never starts native animations.

live_view_count

live_view_count() -> int

Return how many views are currently registered (created and not yet destroyed).

ops_of

ops_of(kind: str) -> List[Any]

Every recorded op tuple whose first element is kind.

detached_views

detached_views(
    type_name: Optional[str] = None,
) -> List[FakeView]

Live views never inserted into a parent (Portal overlays, the root).

FakeView

FakeView(tag: int, type_name: str, props: Dict[str, Any])

Simulated native view: type, props, children, and last frame.

Attributes:

Name Type Description
tag

The reconciler-assigned tag (use with fire / events).

type_name

Native type, e.g. "Text".

props Dict[str, Any]

Native-safe props (event callbacks are stripped; they live in the event registry keyed by tag).

children List[FakeView]

Child views in order.

frame Tuple[float, float, float, float]

(x, y, width, height) from the last layout pass.

Methods:

Name Description
walk

Yield this view and every descendant, depth-first.

find_all

Every view in this subtree matching a type name or predicate.

find_first

Return the first view in this subtree matching a type name or predicate, or None.

dump

Indented, human-readable subtree (for failing-test output).

text property

text: Optional[str]

Visible text for text-bearing views (Text.text, Button.title, TextInput.value).

hidden property

hidden: bool

Whether this view is removed from layout (display: "none").

test_id property

test_id: Optional[str]

The test_id prop, if set.

label property

label: Optional[str]

The accessibility_label prop, if set.

walk

walk(
    *, include_hidden: bool = True
) -> Iterator["FakeView"]

Yield this view and every descendant, depth-first.

With include_hidden=False subtrees under a display: "none" view are skipped (what a user can see).

find_all

find_all(predicate_or_type: Any) -> List['FakeView']

Every view in this subtree matching a type name or predicate.

find_first

find_first(predicate_or_type: Any) -> Optional['FakeView']

Return the first view in this subtree matching a type name or predicate, or None.

dump

dump(indent: int = 0) -> str

Indented, human-readable subtree (for failing-test output).

FakeHost

FakeHost(initial_state: Optional[Dict[str, Any]] = None)

A HostNavigator that records native screen operations.

Pass as render(..., host=FakeHost()) to render a root stack the way a device would: pushes are recorded in pushed instead of creating screens in-tree. set_focused simulates the platform covering / revealing the screen.

Methods:

Name Description
initial_navigation_state

Return the initial_state the host was constructed with (None for a fresh root).

push_screen

Record the push in pushed instead of creating a native screen.

pop_screens

Record the requested pop count in popped.

replace_screen

Record the replacement in replaced instead of swapping a native screen.

reset_screens

Record the stack reset in resets instead of rebuilding native screens.

set_screen_options

Append a copy of options to options (see the title property).

add_focus_listener

Register a focus callback fired by set_focused; returns an unsubscribe callable.

set_focused

Simulate the platform covering (False) or revealing (True) the screen.

Attributes:

Name Type Description
title Optional[str]

The most recent title passed to set_screen_options.

title property

title: Optional[str]

The most recent title passed to set_screen_options.

initial_navigation_state

initial_navigation_state() -> Optional[Dict[str, Any]]

Return the initial_state the host was constructed with (None for a fresh root).

push_screen

push_screen(
    state: Dict[str, Any], options: Dict[str, Any]
) -> None

Record the push in pushed instead of creating a native screen.

pop_screens

pop_screens(count: int) -> None

Record the requested pop count in popped.

replace_screen

replace_screen(
    state: Dict[str, Any], options: Dict[str, Any]
) -> None

Record the replacement in replaced instead of swapping a native screen.

reset_screens

reset_screens(
    state: Dict[str, Any], options: Dict[str, Any]
) -> None

Record the stack reset in resets instead of rebuilding native screens.

set_screen_options

set_screen_options(options: Dict[str, Any]) -> None

Append a copy of options to options (see the title property).

add_focus_listener

add_focus_listener(
    callback: Callable[[bool], None],
) -> Callable[[], None]

Register a focus callback fired by set_focused; returns an unsubscribe callable.

set_focused

set_focused(focused: bool) -> None

Simulate the platform covering (False) or revealing (True) the screen.

HookResult

HookResult(
    result: RenderResult,
    box: Dict[str, Any],
    rerender: Callable[..., None],
)

Bases: Generic[T]

Handle returned by render_hook.

Attributes:

Name Type Description
current T

The hook's most recent return value.

Methods:

Name Description
act

Run fn (typically a state setter) and settle.

rerender

Re-run the hook with new arguments.

settle

Flush pending renders and async work started by the hook.

unmount

Unmount the harness component, running the hook's effect cleanups.

current property

current: T

The value the hook returned on its most recent render.

render_count property

render_count: int

How many times the hook has run since render_hook was called.

act

act(fn: Callable[[], Any]) -> None

Run fn (typically a state setter) and settle.

rerender

rerender(*args: Any, **kwargs: Any) -> None

Re-run the hook with new arguments.

settle

settle() -> None

Flush pending renders and async work started by the hook.

unmount

unmount() -> None

Unmount the harness component, running the hook's effect cleanups.

RenderResult

RenderResult(
    reconciler: Any,
    backend: FakeBackend,
    wrap: Callable[[Node], Element],
)

Handle to a mounted tree: queries, events, re-render, unmount.

Query methods come in three flavors, mirroring Testing Library: get_by_* returns exactly one match or raises LookupError (with the tree dumped in the message), query_by_* returns the match or None, get_all_by_* returns every match. Matchers are exact strings, compiled regexes, or predicates. Views inside a display: "none" subtree (inactive tabs, covered stack screens) are skipped unless hidden=True is passed.

Methods:

Name Description
views

Every live view, root first (includes detached Portal overlays).

dump

Indented text rendering of the live tree.

text

Visible strings in document order.

get_all_by_text

Return every view whose visible text matches matcher (exact=False matches substrings).

get_by_text

Return the single view whose visible text matches matcher; raise LookupError otherwise.

query_by_text

Return the first view whose visible text matches matcher, or None.

get_all_by_test_id

Return every view whose test_id prop matches matcher.

get_by_test_id

Return the single view whose test_id prop matches matcher; raise LookupError otherwise.

query_by_test_id

Return the first view whose test_id prop matches matcher, or None.

get_all_by_label

Return every view whose accessibility_label prop matches matcher.

get_by_label

Return the single view whose accessibility_label matches matcher; raise LookupError if not.

query_by_label

Return the first view whose accessibility_label prop matches matcher, or None.

get_all_by_type

Return every view of native type type_name (for example "Text").

get_by_type

Return the single view of native type type_name; raise LookupError otherwise.

query_by_type

Return the first view of native type type_name, or None.

fire

Dispatch event (an on_* prop name) to target and settle.

press

Fire on_press on target.

change_text

Fire on_change_text on a TextInput.

back

Simulate the system back action; returns whether a handler consumed it.

settle

Flush pending renders and async work (see settle).

rerender

Reconcile a new root element (new props from outside the tree).

unmount

Unmount the tree, running effect cleanups and destroying every view.

Attributes:

Name Type Description
root Optional[FakeView]

The root native view (None after unmount).

root property

The root native view (None after unmount).

views

views(*, hidden: bool = False) -> List[FakeView]

Every live view, root first (includes detached Portal overlays).

dump

dump() -> str

Indented text rendering of the live tree.

text

text(*, hidden: bool = False) -> List[str]

Visible strings in document order.

get_all_by_text

get_all_by_text(
    matcher: Matcher,
    *,
    exact: bool = True,
    hidden: bool = False
) -> List[FakeView]

Return every view whose visible text matches matcher (exact=False matches substrings).

get_by_text

get_by_text(
    matcher: Matcher,
    *,
    exact: bool = True,
    hidden: bool = False
) -> FakeView

Return the single view whose visible text matches matcher; raise LookupError otherwise.

query_by_text

query_by_text(
    matcher: Matcher,
    *,
    exact: bool = True,
    hidden: bool = False
) -> Optional[FakeView]

Return the first view whose visible text matches matcher, or None.

get_all_by_test_id

get_all_by_test_id(
    matcher: Matcher, *, hidden: bool = False
) -> List[FakeView]

Return every view whose test_id prop matches matcher.

get_by_test_id

get_by_test_id(
    matcher: Matcher, *, hidden: bool = False
) -> FakeView

Return the single view whose test_id prop matches matcher; raise LookupError otherwise.

query_by_test_id

query_by_test_id(
    matcher: Matcher, *, hidden: bool = False
) -> Optional[FakeView]

Return the first view whose test_id prop matches matcher, or None.

get_all_by_label

get_all_by_label(
    matcher: Matcher, *, hidden: bool = False
) -> List[FakeView]

Return every view whose accessibility_label prop matches matcher.

get_by_label

get_by_label(
    matcher: Matcher, *, hidden: bool = False
) -> FakeView

Return the single view whose accessibility_label matches matcher; raise LookupError if not.

query_by_label

query_by_label(
    matcher: Matcher, *, hidden: bool = False
) -> Optional[FakeView]

Return the first view whose accessibility_label prop matches matcher, or None.

get_all_by_type

get_all_by_type(
    type_name: str, *, hidden: bool = False
) -> List[FakeView]

Return every view of native type type_name (for example "Text").

get_by_type

get_by_type(
    type_name: str, *, hidden: bool = False
) -> FakeView

Return the single view of native type type_name; raise LookupError otherwise.

query_by_type

query_by_type(
    type_name: str, *, hidden: bool = False
) -> Optional[FakeView]

Return the first view of native type type_name, or None.

fire

fire(target: Target, event: str, *args: Any) -> None

Dispatch event (an on_* prop name) to target and settle.

Raises:

Type Description
LookupError

If no handler is registered for the event.

press

press(target: Target) -> None

Fire on_press on target.

change_text

change_text(target: Target, value: str) -> None

Fire on_change_text on a TextInput.

back

back() -> bool

Simulate the system back action; returns whether a handler consumed it.

settle

settle(timeout: float = 1.0) -> None

Flush pending renders and async work (see settle).

rerender

rerender(element: Node) -> None

Reconcile a new root element (new props from outside the tree).

unmount

unmount() -> None

Unmount the tree, running effect cleanups and destroying every view.

render

render(
    element: Node,
    *,
    viewport: Optional[
        Tuple[float, float]
    ] = DEFAULT_VIEWPORT,
    backend: Optional[FakeBackend] = None,
    host: Optional[FakeHost] = None,
    settle_first: bool = True
) -> RenderResult

Mount element into a FakeBackend.

Parameters:

Name Type Description Default
element Node

The element (or component call) to render.

required
viewport Optional[Tuple[float, float]]

Size for the layout pass; None skips layout.

DEFAULT_VIEWPORT
backend Optional[FakeBackend]

Reuse an existing backend (defaults to a fresh one).

None
host Optional[FakeHost]

Render under a HostRoot with this fake host, so root stacks push native screens into host.pushed instead of the tree.

None
settle_first bool

Drain async work and effects before returning.

True

render_hook

render_hook(
    hook: Callable[..., T],
    *args: Any,
    host: Optional[FakeHost] = None,
    **kwargs: Any
) -> HookResult[T]

Run hook(*args, **kwargs) inside a throwaway component.

result = render_hook(lambda: pn.use_state(0))
value, set_value = result.current
result.act(lambda: set_value(5))
assert result.current[0] == 5

settle

settle(
    reconciler: Any = None, timeout: float = 1.0
) -> None

Pump the framework loop and flush pending renders until everything is idle.

Use after triggering async work (use_resource, use_query, transitions, coroutines started by handlers) so assertions see the settled tree.

Next steps