mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'css' of github.com:willmcgugan/textual into text-justify
This commit is contained in:
@@ -268,7 +268,7 @@ async def test_scrollbar_gutter(
|
||||
|
||||
text_widget = TextWidget()
|
||||
text_widget.styles.height = "auto"
|
||||
container.add_child(text_widget)
|
||||
container._add_child(text_widget)
|
||||
|
||||
class MyTestApp(AppTest):
|
||||
def compose(self) -> ComposeResult:
|
||||
|
||||
@@ -21,7 +21,7 @@ def test_nodes_take_display_property_into_account_when_they_display_their_childr
|
||||
|
||||
screen = Screen()
|
||||
screen.styles.layout = layout
|
||||
screen.add_child(widget)
|
||||
screen._add_child(widget)
|
||||
|
||||
displayed_children = screen.displayed_children
|
||||
assert isinstance(displayed_children, list)
|
||||
|
||||
@@ -243,7 +243,7 @@ def test_bound_animator():
|
||||
assert animator._animations[(id(animate_test), "foo")] == expected
|
||||
|
||||
|
||||
def test_animator_on_complete_callback_not_fired_before_duration_ends():
|
||||
async def test_animator_on_complete_callback_not_fired_before_duration_ends():
|
||||
callback = Mock()
|
||||
animate_test = AnimateTest()
|
||||
animator = MockAnimator(Mock())
|
||||
@@ -251,7 +251,7 @@ def test_animator_on_complete_callback_not_fired_before_duration_ends():
|
||||
animator.animate(animate_test, "foo", 200, duration=10, on_complete=callback)
|
||||
|
||||
animator._time = 9
|
||||
animator()
|
||||
await animator()
|
||||
|
||||
assert not callback.called
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ def parent():
|
||||
child1 = DOMNode(id="child1")
|
||||
child2 = DOMNode(id="child2")
|
||||
grandchild1 = DOMNode(id="grandchild1")
|
||||
child1.add_child(grandchild1)
|
||||
child1._add_child(grandchild1)
|
||||
|
||||
parent.add_child(child1)
|
||||
parent.add_child(child2)
|
||||
parent._add_child(child1)
|
||||
parent._add_child(child2)
|
||||
|
||||
yield parent
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ async def test_focus_chain():
|
||||
# Check empty focus chain
|
||||
assert not app.focus_chain
|
||||
|
||||
app.screen.add_children(
|
||||
app.screen._add_children(
|
||||
Focusable(id="foo"),
|
||||
NonFocusable(id="bar"),
|
||||
Focusable(Focusable(id="Paul"), id="container1"),
|
||||
@@ -37,7 +37,7 @@ async def test_focus_next_and_previous():
|
||||
app = App()
|
||||
app._set_active()
|
||||
app.push_screen(Screen())
|
||||
app.screen.add_children(
|
||||
app.screen._add_children(
|
||||
Focusable(id="foo"),
|
||||
NonFocusable(id="bar"),
|
||||
Focusable(Focusable(id="Paul"), id="container1"),
|
||||
|
||||
@@ -11,8 +11,8 @@ def test_query():
|
||||
app = App()
|
||||
main_view = View(id="main")
|
||||
help_view = View(id="help")
|
||||
app.add_child(main_view)
|
||||
app.add_child(help_view)
|
||||
app._add_child(main_view)
|
||||
app._add_child(help_view)
|
||||
|
||||
widget1 = Widget(id="widget1")
|
||||
widget2 = Widget(id="widget2")
|
||||
@@ -22,21 +22,21 @@ def test_query():
|
||||
helpbar = Widget(id="helpbar")
|
||||
helpbar.add_class("float")
|
||||
|
||||
main_view.add_child(widget1)
|
||||
main_view.add_child(widget2)
|
||||
main_view.add_child(sidebar)
|
||||
main_view._add_child(widget1)
|
||||
main_view._add_child(widget2)
|
||||
main_view._add_child(sidebar)
|
||||
|
||||
sub_view = View(id="sub")
|
||||
sub_view.add_class("-subview")
|
||||
main_view.add_child(sub_view)
|
||||
main_view._add_child(sub_view)
|
||||
|
||||
tooltip = Widget(id="tooltip")
|
||||
tooltip.add_class("float", "transient")
|
||||
sub_view.add_child(tooltip)
|
||||
sub_view._add_child(tooltip)
|
||||
|
||||
help = Widget(id="markdown")
|
||||
help_view.add_child(help)
|
||||
help_view.add_child(helpbar)
|
||||
help_view._add_child(help)
|
||||
help_view._add_child(helpbar)
|
||||
|
||||
# repeat tests to account for caching
|
||||
for repeat in range(3):
|
||||
|
||||
@@ -37,7 +37,7 @@ def parser():
|
||||
return XTermParser(sender=mock.sentinel, more_data=lambda: False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("chunk_size", [2,3,4,5,6])
|
||||
@pytest.mark.parametrize("chunk_size", [2, 3, 4, 5, 6])
|
||||
def test_varying_parser_chunk_sizes_no_missing_data(parser, chunk_size):
|
||||
end = "\x1b[8~"
|
||||
text = "ABCDEFGH"
|
||||
@@ -54,7 +54,7 @@ def test_varying_parser_chunk_sizes_no_missing_data(parser, chunk_size):
|
||||
|
||||
|
||||
def test_bracketed_paste(parser):
|
||||
""" When bracketed paste mode is enabled in the terminal emulator and
|
||||
"""When bracketed paste mode is enabled in the terminal emulator and
|
||||
the user pastes in some text, it will surround the pasted input
|
||||
with the escape codes "\x1b[200~" and "\x1b[201~". The text between
|
||||
these codes corresponds to a single `Paste` event in Textual.
|
||||
@@ -90,7 +90,7 @@ def test_bracketed_paste_amongst_other_codes(parser):
|
||||
|
||||
|
||||
def test_cant_match_escape_sequence_too_long(parser):
|
||||
""" The sequence did not match, and we hit the maximum sequence search
|
||||
"""The sequence did not match, and we hit the maximum sequence search
|
||||
length threshold, so each character should be issued as a key-press instead.
|
||||
"""
|
||||
sequence = "\x1b[123456789123456789123"
|
||||
@@ -109,15 +109,22 @@ def test_cant_match_escape_sequence_too_long(parser):
|
||||
assert events[index].key == character
|
||||
|
||||
|
||||
@pytest.mark.parametrize("chunk_size", [
|
||||
pytest.param(2, marks=pytest.mark.xfail(reason="Fails when ESC at end of chunk")),
|
||||
3,
|
||||
pytest.param(4, marks=pytest.mark.xfail(reason="Fails when ESC at end of chunk")),
|
||||
5,
|
||||
6,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"chunk_size",
|
||||
[
|
||||
pytest.param(
|
||||
2, marks=pytest.mark.xfail(reason="Fails when ESC at end of chunk")
|
||||
),
|
||||
3,
|
||||
pytest.param(
|
||||
4, marks=pytest.mark.xfail(reason="Fails when ESC at end of chunk")
|
||||
),
|
||||
5,
|
||||
6,
|
||||
],
|
||||
)
|
||||
def test_unknown_sequence_followed_by_known_sequence(parser, chunk_size):
|
||||
""" When we feed the parser an unknown sequence followed by a known
|
||||
"""When we feed the parser an unknown sequence followed by a known
|
||||
sequence. The characters in the unknown sequence are delivered as keys,
|
||||
and the known escape sequence that follows is delivered as expected.
|
||||
"""
|
||||
@@ -174,16 +181,19 @@ def test_double_escape(parser):
|
||||
assert [event.key for event in events] == ["escape"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sequence, event_type, shift, meta", [
|
||||
# Mouse down, with and without modifiers
|
||||
("\x1b[<0;50;25M", MouseDown, False, False),
|
||||
("\x1b[<4;50;25M", MouseDown, True, False),
|
||||
("\x1b[<8;50;25M", MouseDown, False, True),
|
||||
# Mouse up, with and without modifiers
|
||||
("\x1b[<0;50;25m", MouseUp, False, False),
|
||||
("\x1b[<4;50;25m", MouseUp, True, False),
|
||||
("\x1b[<8;50;25m", MouseUp, False, True),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, event_type, shift, meta",
|
||||
[
|
||||
# Mouse down, with and without modifiers
|
||||
("\x1b[<0;50;25M", MouseDown, False, False),
|
||||
("\x1b[<4;50;25M", MouseDown, True, False),
|
||||
("\x1b[<8;50;25M", MouseDown, False, True),
|
||||
# Mouse up, with and without modifiers
|
||||
("\x1b[<0;50;25m", MouseUp, False, False),
|
||||
("\x1b[<4;50;25m", MouseUp, True, False),
|
||||
("\x1b[<8;50;25m", MouseUp, False, True),
|
||||
],
|
||||
)
|
||||
def test_mouse_click(parser, sequence, event_type, shift, meta):
|
||||
"""ANSI codes for mouse should be converted to Textual events"""
|
||||
events = list(parser.feed(sequence))
|
||||
@@ -201,12 +211,15 @@ def test_mouse_click(parser, sequence, event_type, shift, meta):
|
||||
assert event.shift is shift
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sequence, shift, meta, button", [
|
||||
("\x1b[<32;15;38M", False, False, 1), # Click and drag
|
||||
("\x1b[<35;15;38M", False, False, 0), # Basic cursor movement
|
||||
("\x1b[<39;15;38M", True, False, 0), # Shift held down
|
||||
("\x1b[<43;15;38M", False, True, 0), # Meta held down
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, shift, meta, button",
|
||||
[
|
||||
("\x1b[<32;15;38M", False, False, 1), # Click and drag
|
||||
("\x1b[<35;15;38M", False, False, 0), # Basic cursor movement
|
||||
("\x1b[<39;15;38M", True, False, 0), # Shift held down
|
||||
("\x1b[<43;15;38M", False, True, 0), # Meta held down
|
||||
],
|
||||
)
|
||||
def test_mouse_move(parser, sequence, shift, meta, button):
|
||||
events = list(parser.feed(sequence))
|
||||
|
||||
@@ -222,12 +235,15 @@ def test_mouse_move(parser, sequence, shift, meta, button):
|
||||
assert event.button == button
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sequence", [
|
||||
"\x1b[<64;18;25M",
|
||||
"\x1b[<68;18;25M",
|
||||
"\x1b[<72;18;25M",
|
||||
])
|
||||
def test_mouse_scroll_down(parser, sequence):
|
||||
@pytest.mark.parametrize(
|
||||
"sequence",
|
||||
[
|
||||
"\x1b[<64;18;25M",
|
||||
"\x1b[<68;18;25M",
|
||||
"\x1b[<72;18;25M",
|
||||
],
|
||||
)
|
||||
def test_mouse_scroll_up(parser, sequence):
|
||||
"""Scrolling the mouse with and without modifiers held down.
|
||||
We don't currently capture modifier keys in scroll events.
|
||||
"""
|
||||
@@ -237,24 +253,27 @@ def test_mouse_scroll_down(parser, sequence):
|
||||
|
||||
event = events[0]
|
||||
|
||||
assert isinstance(event, MouseScrollDown)
|
||||
assert isinstance(event, MouseScrollUp)
|
||||
assert event.x == 17
|
||||
assert event.y == 24
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sequence, shift, meta", [
|
||||
("\x1b[<65;18;25M", False, False),
|
||||
("\x1b[<69;18;25M", True, False),
|
||||
("\x1b[<73;18;25M", False, True),
|
||||
])
|
||||
def test_mouse_scroll_up(parser, sequence, shift, meta):
|
||||
@pytest.mark.parametrize(
|
||||
"sequence",
|
||||
[
|
||||
"\x1b[<65;18;25M",
|
||||
"\x1b[<69;18;25M",
|
||||
"\x1b[<73;18;25M",
|
||||
],
|
||||
)
|
||||
def test_mouse_scroll_down(parser, sequence):
|
||||
events = list(parser.feed(sequence))
|
||||
|
||||
assert len(events) == 1
|
||||
|
||||
event = events[0]
|
||||
|
||||
assert isinstance(event, MouseScrollUp)
|
||||
assert isinstance(event, MouseScrollDown)
|
||||
assert event.x == 17
|
||||
assert event.y == 24
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class AppTest(App):
|
||||
waiting_duration_after_yield: float = 0,
|
||||
) -> AsyncContextManager[ClockMock]:
|
||||
async def run_app() -> None:
|
||||
await self.process_messages()
|
||||
await self._process_messages()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def get_running_state_context_manager():
|
||||
@@ -103,6 +103,7 @@ class AppTest(App):
|
||||
# End of simulated time: we just shut down ourselves:
|
||||
assert not run_task.done()
|
||||
await self.shutdown()
|
||||
await run_task
|
||||
|
||||
return get_running_state_context_manager()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user