mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
@@ -14,5 +14,3 @@ class GridApp(App):
|
||||
|
||||
|
||||
app = GridApp(css_path="grid.css")
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
||||
@@ -13,6 +13,3 @@ class LinksApp(App):
|
||||
|
||||
|
||||
app = LinksApp(css_path="links.css")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
||||
@@ -7,7 +7,9 @@ class CheckboxApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static("[b]Example checkboxes\n", classes="label")
|
||||
yield Horizontal(
|
||||
Static("off: ", classes="label"), Checkbox(), classes="container"
|
||||
Static("off: ", classes="label"),
|
||||
Checkbox(animate=False),
|
||||
classes="container",
|
||||
)
|
||||
yield Horizontal(
|
||||
Static("on: ", classes="label"),
|
||||
|
||||
@@ -4,7 +4,16 @@ from textual.widgets import Footer
|
||||
|
||||
|
||||
class FooterApp(App):
|
||||
BINDINGS = [Binding(key="q", action="quit", description="Quit the app")]
|
||||
BINDINGS = [
|
||||
Binding(key="q", action="quit", description="Quit the app"),
|
||||
Binding(
|
||||
key="question_mark",
|
||||
action="help",
|
||||
description="Show help screen",
|
||||
key_display="?",
|
||||
),
|
||||
Binding(key="j", action="down", description="Scroll down", show=False),
|
||||
]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Footer()
|
||||
|
||||
@@ -11,13 +11,13 @@ The example below populates a table with CSV data.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/table.py"}
|
||||
```{.textual path="docs/examples/widgets/data_table.py"}
|
||||
```
|
||||
|
||||
=== "table.py"
|
||||
=== "data_table.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/table.py"
|
||||
--8<-- "docs/examples/widgets/data_table.py"
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
assert press
|
||||
driver = app._driver
|
||||
assert driver is not None
|
||||
await asyncio.sleep(0.01)
|
||||
await asyncio.sleep(0.02)
|
||||
for key in press:
|
||||
if key == "_":
|
||||
print("(pause 50ms)")
|
||||
@@ -632,7 +632,13 @@ class App(Generic[ReturnType], DOMNode):
|
||||
print(f"press {key!r} (char={char!r})")
|
||||
key_event = events.Key(self, key, char)
|
||||
driver.send_event(key_event)
|
||||
await asyncio.sleep(0.01)
|
||||
# TODO: A bit of a fudge - extra sleep after tabbing to help guard against race
|
||||
# condition between widget-level key handling and app/screen level handling.
|
||||
# More information here: https://github.com/Textualize/textual/issues/1009
|
||||
# This conditional sleep can be removed after that issue is closed.
|
||||
if key == "tab":
|
||||
await asyncio.sleep(0.05)
|
||||
await asyncio.sleep(0.02)
|
||||
|
||||
await app._animator.wait_for_idle()
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -59,6 +59,7 @@ def snap_compare(
|
||||
"""
|
||||
node = request.node
|
||||
app = import_app(app_path)
|
||||
compare.app = app
|
||||
actual_screenshot = take_svg_screenshot(
|
||||
app=app,
|
||||
press=press,
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
import pytest
|
||||
|
||||
from textual.app import App
|
||||
from textual.widgets import Input, Button
|
||||
|
||||
|
||||
# --- Layout related stuff ---
|
||||
|
||||
def test_grid_layout_basic(snap_compare):
|
||||
assert snap_compare("docs/examples/guide/layout/grid_layout1.py")
|
||||
|
||||
@@ -26,7 +36,73 @@ def test_dock_layout_sidebar(snap_compare):
|
||||
assert snap_compare("docs/examples/guide/layout/dock_layout2_sidebar.py")
|
||||
|
||||
|
||||
# --- Widgets - rendering and basic interactions ---
|
||||
# Each widget should have a canonical example that is display in the docs.
|
||||
# When adding a new widget, ideally we should also create a snapshot test
|
||||
# from these examples which test rendering and simple interactions with it.
|
||||
|
||||
def test_checkboxes(snap_compare):
|
||||
"""Tests checkboxes but also acts a regression test for using
|
||||
width: auto in a Horizontal layout context."""
|
||||
assert snap_compare("docs/examples/widgets/checkbox.py")
|
||||
press = [
|
||||
"shift+tab",
|
||||
"enter", # toggle off
|
||||
"shift+tab",
|
||||
"wait:20",
|
||||
"enter", # toggle on
|
||||
"wait:20",
|
||||
]
|
||||
assert snap_compare("docs/examples/widgets/checkbox.py", press=press)
|
||||
|
||||
|
||||
def test_input_and_focus(snap_compare):
|
||||
press = [
|
||||
"tab",
|
||||
*"Darren", # Focus first input, write "Darren"
|
||||
"tab",
|
||||
*"Burns", # Tab focus to second input, write "Burns"
|
||||
]
|
||||
assert snap_compare("docs/examples/widgets/input.py", press=press)
|
||||
|
||||
# Assert that the state of the Input is what we'd expect
|
||||
app: App = snap_compare.app
|
||||
input: Input = app.query_one(Input)
|
||||
assert input.value == "Darren"
|
||||
assert input.cursor_position == 6
|
||||
assert input.view_position == 0
|
||||
|
||||
|
||||
def test_buttons_render(snap_compare):
|
||||
# Testing button rendering. We press tab to focus the first button too.
|
||||
assert snap_compare("docs/examples/widgets/button.py", press=["tab"])
|
||||
|
||||
app = snap_compare.app
|
||||
button: Button = app.query_one(Button)
|
||||
assert app.focused is button
|
||||
|
||||
|
||||
def test_datatable_render(snap_compare):
|
||||
press = ["tab", "down", "down", "right", "up", "left"]
|
||||
assert snap_compare("docs/examples/widgets/data_table.py", press=press)
|
||||
|
||||
|
||||
def test_footer_render(snap_compare):
|
||||
assert snap_compare("docs/examples/widgets/footer.py")
|
||||
|
||||
|
||||
def test_header_render(snap_compare):
|
||||
assert snap_compare("docs/examples/widgets/header.py")
|
||||
|
||||
|
||||
# --- CSS properties ---
|
||||
# We have a canonical example for each CSS property that is shown in their docs.
|
||||
# If any of these change, something has likely broken, so snapshot each of them.
|
||||
|
||||
PATHS = [
|
||||
str(PurePosixPath(path)) for path in Path("docs/examples/styles").iterdir() if path.suffix == ".py"
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", PATHS)
|
||||
def test_css_property_snapshot(path, snap_compare):
|
||||
assert snap_compare(path)
|
||||
|
||||
Reference in New Issue
Block a user