mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'main' into list-view
This commit is contained in:
28
tests/layouts/test_content_dimensions.py
Normal file
28
tests/layouts/test_content_dimensions.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import pytest
|
||||
|
||||
from textual.layouts.grid import GridLayout
|
||||
from textual.layouts.horizontal import HorizontalLayout
|
||||
from textual.layouts.vertical import VerticalLayout
|
||||
from textual.geometry import Size
|
||||
from textual.widget import Widget
|
||||
|
||||
|
||||
LAYOUTS = [GridLayout, HorizontalLayout, VerticalLayout]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("layout", LAYOUTS)
|
||||
def test_empty_widget_height(layout):
|
||||
"""Test that an empty widget has height equal to 0."""
|
||||
l = layout()
|
||||
# Make sure this measurement does not depend on the width.
|
||||
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 24) == 0
|
||||
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 20) == 0
|
||||
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 10) == 0
|
||||
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 0) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("layout", LAYOUTS)
|
||||
def test_empty_widget_width(layout):
|
||||
"""Test that an empty widget has width equal to 0."""
|
||||
l = layout()
|
||||
assert l.get_content_width(Widget(), Size(80, 24), Size(80, 24)) == 0
|
||||
File diff suppressed because one or more lines are too long
37
tests/snapshot_tests/snapshot_apps/columns_height.py
Normal file
37
tests/snapshot_tests/snapshot_apps/columns_height.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import Horizontal
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class HeightApp(App[None]):
|
||||
|
||||
CSS = """
|
||||
Horizontal {
|
||||
border: solid red;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
Static {
|
||||
border: solid green;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#fill_parent {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#static {
|
||||
height: 16;
|
||||
}
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Horizontal(
|
||||
Static("As tall as container", id="fill_parent"),
|
||||
Static("This has default\nheight\nbut a\nfew lines"),
|
||||
Static("I have a static height", id="static"),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
HeightApp().run()
|
||||
41
tests/snapshot_tests/snapshot_apps/offsets.py
Normal file
41
tests/snapshot_tests/snapshot_apps/offsets.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import Vertical
|
||||
from textual.widgets import Label, Static
|
||||
|
||||
|
||||
class Box(Static):
|
||||
DEFAULT_CSS = """
|
||||
Box {
|
||||
border: solid white;
|
||||
background: darkblue;
|
||||
width: 16;
|
||||
height: auto;
|
||||
}
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Label("FOO\nBAR\nBAZ")
|
||||
|
||||
|
||||
class OffsetsApp(App):
|
||||
|
||||
CSS = """
|
||||
|
||||
#box1 {
|
||||
offset: 5 5;
|
||||
}
|
||||
|
||||
#box2 {
|
||||
offset: 15 10;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Box(id="box1")
|
||||
yield Box(id="box2")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = OffsetsApp()
|
||||
app.run()
|
||||
75
tests/snapshot_tests/snapshot_apps/order_independence.py
Normal file
75
tests/snapshot_tests/snapshot_apps/order_independence.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Label
|
||||
from textual.containers import Vertical, Container
|
||||
|
||||
|
||||
class Overlay(Container):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Label("This should float over the top")
|
||||
|
||||
|
||||
class Body1(Vertical):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Label("My God! It's full of stars! " * 300)
|
||||
|
||||
|
||||
class Body2(Vertical):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Label("My God! It's full of stars! " * 300)
|
||||
|
||||
|
||||
class Good(Screen):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
yield Overlay()
|
||||
yield Body1()
|
||||
yield Footer()
|
||||
|
||||
|
||||
class Bad(Screen):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Overlay()
|
||||
yield Header()
|
||||
yield Body2()
|
||||
yield Footer()
|
||||
|
||||
|
||||
class Layers(App[None]):
|
||||
|
||||
CSS = """
|
||||
Screen {
|
||||
layers: base higher;
|
||||
}
|
||||
|
||||
Overlay {
|
||||
layer: higher;
|
||||
dock: top;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 2;
|
||||
border: solid yellow;
|
||||
background: red;
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
Body2 {
|
||||
background: green;
|
||||
}
|
||||
"""
|
||||
|
||||
SCREENS = {"good": Good, "bad": Bad}
|
||||
|
||||
BINDINGS = [("t", "toggle", "Toggle Screen")]
|
||||
|
||||
def on_mount(self):
|
||||
self.push_screen("good")
|
||||
|
||||
def action_toggle(self):
|
||||
self.switch_screen(
|
||||
"bad" if self.screen.__class__.__name__ == "Good" else "good"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Layers().run()
|
||||
48
tests/snapshot_tests/snapshot_apps/visibility.py
Normal file
48
tests/snapshot_tests/snapshot_apps/visibility.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from textual.app import App
|
||||
from textual.containers import Vertical
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class Visibility(App):
|
||||
"""Check that visibility: hidden also makes children invisible;"""
|
||||
|
||||
CSS = """
|
||||
Screen {
|
||||
layout: horizontal;
|
||||
}
|
||||
Vertical {
|
||||
width: 1fr;
|
||||
border: solid red;
|
||||
}
|
||||
|
||||
#container1 {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.float {
|
||||
border: solid blue;
|
||||
}
|
||||
|
||||
/* Make a child of a hidden widget visible again */
|
||||
#container1 .float {
|
||||
visibility: visible;
|
||||
}
|
||||
"""
|
||||
|
||||
def compose(self):
|
||||
|
||||
yield Vertical(
|
||||
Static("foo"),
|
||||
Static("float", classes="float"),
|
||||
id="container1",
|
||||
)
|
||||
yield Vertical(
|
||||
Static("bar"),
|
||||
Static("float", classes="float"),
|
||||
id="container2",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = Visibility()
|
||||
app.run()
|
||||
@@ -2,6 +2,8 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from textual.widgets import Placeholder
|
||||
|
||||
# These paths should be relative to THIS directory.
|
||||
WIDGET_EXAMPLES_DIR = Path("../../docs/examples/widgets")
|
||||
LAYOUT_EXAMPLES_DIR = Path("../../docs/examples/guide/layout")
|
||||
@@ -79,6 +81,12 @@ def test_buttons_render(snap_compare):
|
||||
assert snap_compare(WIDGET_EXAMPLES_DIR / "button.py", press=["tab"])
|
||||
|
||||
|
||||
def test_placeholder_render(snap_compare):
|
||||
# Testing the rendering of the multiple placeholder variants and labels.
|
||||
Placeholder.reset_color_cycle()
|
||||
assert snap_compare(WIDGET_EXAMPLES_DIR / "placeholder.py")
|
||||
|
||||
|
||||
def test_datatable_render(snap_compare):
|
||||
press = ["tab", "down", "down", "right", "up", "left"]
|
||||
assert snap_compare(WIDGET_EXAMPLES_DIR / "data_table.py", press=press)
|
||||
@@ -104,6 +112,10 @@ def test_fr_units(snap_compare):
|
||||
assert snap_compare("snapshot_apps/fr_units.py")
|
||||
|
||||
|
||||
def test_visibility(snap_compare):
|
||||
assert snap_compare("snapshot_apps/visibility.py")
|
||||
|
||||
|
||||
def test_tree_example(snap_compare):
|
||||
assert snap_compare(WIDGET_EXAMPLES_DIR / "tree.py")
|
||||
|
||||
@@ -130,8 +142,31 @@ def test_multiple_css(snap_compare):
|
||||
assert snap_compare("snapshot_apps/multiple_css/multiple_css.py")
|
||||
|
||||
|
||||
def test_order_independence(snap_compare):
|
||||
assert snap_compare("snapshot_apps/order_independence.py")
|
||||
|
||||
|
||||
def test_order_independence_toggle(snap_compare):
|
||||
assert snap_compare("snapshot_apps/order_independence.py", press="t,_")
|
||||
|
||||
|
||||
def test_columns_height(snap_compare):
|
||||
# Interaction with height auto, and relative heights to make columns
|
||||
assert snap_compare("snapshot_apps/columns_height.py")
|
||||
|
||||
|
||||
def test_offsets(snap_compare):
|
||||
"""Test offsets of containers"""
|
||||
assert snap_compare("snapshot_apps/offsets.py")
|
||||
|
||||
|
||||
# --- Other ---
|
||||
|
||||
|
||||
def test_key_display(snap_compare):
|
||||
assert snap_compare(SNAPSHOT_APPS_DIR / "key_display.py")
|
||||
|
||||
|
||||
def test_demo(snap_compare):
|
||||
"""Test the demo app (python -m textual)"""
|
||||
assert snap_compare(Path("../../src/textual/demo.py"))
|
||||
|
||||
@@ -100,7 +100,7 @@ def test_width():
|
||||
|
||||
|
||||
def test_height():
|
||||
"""Test width settings."""
|
||||
"""Test height settings."""
|
||||
styles = Styles()
|
||||
one = Fraction(1)
|
||||
|
||||
@@ -123,7 +123,7 @@ def test_height():
|
||||
)
|
||||
assert box_model == BoxModel(Fraction(54), Fraction(16), Spacing(1, 2, 3, 4))
|
||||
|
||||
# Set width to 100 vw which should make it the width of the parent
|
||||
# Set height to 100 vw which should make it the height of the parent
|
||||
styles.height = "100vh"
|
||||
|
||||
box_model = get_box_model(
|
||||
@@ -131,7 +131,7 @@ def test_height():
|
||||
)
|
||||
assert box_model == BoxModel(Fraction(54), Fraction(24), Spacing(1, 2, 3, 4))
|
||||
|
||||
# Set the width to 100% should make it fill the container size
|
||||
# Set the height to 100% should make it fill the container size
|
||||
styles.height = "100%"
|
||||
|
||||
box_model = get_box_model(
|
||||
@@ -156,6 +156,14 @@ def test_height():
|
||||
)
|
||||
assert box_model == BoxModel(Fraction(54), Fraction(10), Spacing(1, 2, 3, 4))
|
||||
|
||||
# Set height to auto and set content height to 0 to check if box collapses.
|
||||
styles.height = "auto"
|
||||
|
||||
box_model = get_box_model(
|
||||
styles, Size(60, 20), Size(80, 24), one, one, get_auto_width, lambda *_: 0
|
||||
)
|
||||
assert box_model == BoxModel(Fraction(54), Fraction(0), Spacing(1, 2, 3, 4))
|
||||
|
||||
|
||||
def test_max():
|
||||
"""Check that max_width and max_height are respected."""
|
||||
|
||||
15
tests/test_placeholder.py
Normal file
15
tests/test_placeholder.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import pytest
|
||||
|
||||
from textual.widgets import Placeholder
|
||||
from textual.widgets._placeholder import InvalidPlaceholderVariant
|
||||
|
||||
|
||||
def test_invalid_placeholder_variant():
|
||||
with pytest.raises(InvalidPlaceholderVariant):
|
||||
Placeholder(variant="this is clearly not a valid variant!")
|
||||
|
||||
|
||||
def test_invalid_reactive_variant_change():
|
||||
p = Placeholder()
|
||||
with pytest.raises(InvalidPlaceholderVariant):
|
||||
p.variant = "this is clearly not a valid variant!"
|
||||
Reference in New Issue
Block a user