mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Add unit tests for App._on_remove
These tests are designed to give 100% coverage to the App._on_remove method, which is the heart of the widget removal system. This is done in anticipation to some reworking as part of #1094. Note that, for the moment, there's a bit of a hack in here. These tests need the pilot. The pilot would need that we await changes to the DOM. Removing things from the DOM changes the DOM. Remove can't be awaited (see above change that's coming). So... until such a time as we can await a remove, we go with a simple await of asyncio.sleep to get things started. Once #1094 has been done these tests should all still work fine *and* we should be able to await the removes rather than use the sleeps.
This commit is contained in:
127
tests/test_widget_removing.py
Normal file
127
tests/test_widget_removing.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import asyncio
|
||||
from textual.app import App
|
||||
from textual.widget import Widget
|
||||
from textual.widgets import Static, Button
|
||||
from textual.containers import Container
|
||||
|
||||
async def await_remove_standin():
|
||||
"""Standin function for awaiting removal.
|
||||
|
||||
These tests are being written so that we can go on and make remove
|
||||
awaitable, but it would be good to have some tests in place *before* we
|
||||
make that change, but the tests need to await remove to be useful tests.
|
||||
So to get around that bootstrap issue, we just use this function as a
|
||||
standin until we can swap over.
|
||||
"""
|
||||
await asyncio.sleep(0) # Until we can await remove.
|
||||
|
||||
async def test_remove_single_widget():
|
||||
"""It should be possible to the only widget on a screen."""
|
||||
async with App().run_test() as pilot:
|
||||
await pilot.app.mount(Static())
|
||||
assert len(pilot.app.screen.children) == 1
|
||||
pilot.app.query_one(Static).remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.children) == 0
|
||||
|
||||
async def test_many_remove_all_widgets():
|
||||
"""It should be possible to remove all widgets on a multi-widget screen."""
|
||||
async with App().run_test() as pilot:
|
||||
await pilot.app.mount(*[Static() for _ in range(1000)])
|
||||
assert len(pilot.app.screen.children) == 1000
|
||||
pilot.app.query(Static).remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.children) == 0
|
||||
|
||||
async def test_many_remove_some_widgets():
|
||||
"""It should be possible to remove some widgets on a multi-widget screen."""
|
||||
async with App().run_test() as pilot:
|
||||
await pilot.app.mount(*[Static(id=f"is-{n%2}") for n in range(1000)])
|
||||
assert len(pilot.app.screen.children) == 1000
|
||||
pilot.app.query("#is-0").remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.children) == 500
|
||||
|
||||
async def test_remove_branch():
|
||||
"""It should be possible to remove a whole branch in the DOM."""
|
||||
async with App().run_test() as pilot:
|
||||
await pilot.app.mount(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Static()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Static(),
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Static()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 13
|
||||
pilot.app.screen.children[0].remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 7
|
||||
|
||||
async def test_remove_overlap():
|
||||
"""It should be possible to remove an overlapping collection of widgets."""
|
||||
async with App().run_test() as pilot:
|
||||
await pilot.app.mount(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Static()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Static(),
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Container(
|
||||
Static()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 13
|
||||
pilot.app.query(Container).remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 1
|
||||
|
||||
async def test_remove_move_focus():
|
||||
"""Removing a focused widget should settle focus elsewhere."""
|
||||
async with App().run_test() as pilot:
|
||||
buttons = [ Button(str(n)) for n in range(10)]
|
||||
await pilot.app.mount(Container(*buttons[:5]), Container(*buttons[5:]))
|
||||
assert len(pilot.app.screen.children) == 2
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 12
|
||||
assert pilot.app.focused is None
|
||||
await pilot.press( "tab" )
|
||||
assert pilot.app.focused is not None
|
||||
assert pilot.app.focused == buttons[0]
|
||||
pilot.app.screen.children[0].remove()
|
||||
await await_remove_standin()
|
||||
assert len(pilot.app.screen.children) == 1
|
||||
assert len(pilot.app.screen.walk_children(with_self=False)) == 6
|
||||
assert pilot.app.focused is not None
|
||||
assert pilot.app.focused == buttons[9]
|
||||
Reference in New Issue
Block a user