ratatui_ruby 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +14 -12
- data/.builds/ruby-3.3.yml +14 -12
- data/.builds/ruby-3.4.yml +14 -12
- data/.builds/ruby-4.0.0.yml +14 -12
- data/AGENTS.md +54 -13
- data/CHANGELOG.md +186 -1
- data/README.md +17 -15
- data/doc/application_architecture.md +116 -0
- data/doc/application_testing.md +12 -7
- data/doc/contributors/better_dx.md +543 -0
- data/doc/contributors/design/ruby_frontend.md +1 -1
- data/doc/contributors/developing_examples.md +203 -0
- data/doc/contributors/documentation_style.md +97 -0
- data/doc/contributors/dwim_dx.md +366 -0
- data/doc/contributors/example_analysis.md +82 -0
- data/doc/custom.css +14 -0
- data/doc/event_handling.md +119 -0
- data/doc/images/all_events.png +0 -0
- data/doc/images/analytics.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/custom_widget.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/hit_test.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/list_styles.png +0 -0
- data/doc/images/login_form.png +0 -0
- data/doc/images/map_demo.png +0 -0
- data/doc/images/mouse_events.png +0 -0
- data/doc/images/popup_demo.png +0 -0
- data/doc/images/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.png +0 -0
- data/doc/images/ratatui_logo_demo.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/rich_text.png +0 -0
- data/doc/images/scroll_text.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/doc/images/table_select.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/index.md +1 -0
- data/doc/interactive_design.md +121 -0
- data/doc/quickstart.md +147 -72
- data/examples/all_events/app.rb +169 -0
- data/examples/all_events/app.rbs +7 -0
- data/examples/all_events/test_app.rb +139 -0
- data/examples/analytics/app.rb +258 -0
- data/examples/analytics/app.rbs +7 -0
- data/examples/analytics/test_app.rb +132 -0
- data/examples/block_padding/app.rb +63 -0
- data/examples/block_padding/app.rbs +7 -0
- data/examples/block_padding/test_app.rb +31 -0
- data/examples/block_titles/app.rb +61 -0
- data/examples/block_titles/app.rbs +7 -0
- data/examples/block_titles/test_app.rb +34 -0
- data/examples/box_demo/app.rb +216 -0
- data/examples/box_demo/app.rbs +7 -0
- data/examples/box_demo/test_app.rb +88 -0
- data/examples/calendar_demo/app.rb +101 -0
- data/examples/calendar_demo/app.rbs +7 -0
- data/examples/calendar_demo/test_app.rb +108 -0
- data/examples/cell_demo/app.rb +108 -0
- data/examples/cell_demo/app.rbs +7 -0
- data/examples/cell_demo/test_app.rb +36 -0
- data/examples/chart_demo/app.rb +203 -0
- data/examples/chart_demo/app.rbs +7 -0
- data/examples/chart_demo/test_app.rb +102 -0
- data/examples/custom_widget/app.rb +51 -0
- data/examples/custom_widget/app.rbs +7 -0
- data/examples/custom_widget/test_app.rb +30 -0
- data/examples/flex_layout/app.rb +156 -0
- data/examples/flex_layout/app.rbs +7 -0
- data/examples/flex_layout/test_app.rb +65 -0
- data/examples/gauge_demo/app.rb +182 -0
- data/examples/gauge_demo/app.rbs +7 -0
- data/examples/gauge_demo/test_app.rb +120 -0
- data/examples/hit_test/app.rb +175 -0
- data/examples/hit_test/app.rbs +7 -0
- data/examples/hit_test/test_app.rb +102 -0
- data/examples/line_gauge_demo/app.rb +190 -0
- data/examples/line_gauge_demo/app.rbs +7 -0
- data/examples/line_gauge_demo/test_app.rb +129 -0
- data/examples/list_demo/app.rb +253 -0
- data/examples/list_demo/app.rbs +12 -0
- data/examples/list_demo/test_app.rb +237 -0
- data/examples/list_styles/app.rb +140 -0
- data/examples/list_styles/app.rbs +7 -0
- data/examples/list_styles/test_app.rb +157 -0
- data/examples/{login_form.rb → login_form/app.rb} +12 -16
- data/examples/login_form/app.rbs +7 -0
- data/examples/login_form/test_app.rb +51 -0
- data/examples/map_demo/app.rb +90 -0
- data/examples/map_demo/app.rbs +7 -0
- data/examples/map_demo/test_app.rb +149 -0
- data/examples/{mouse_events.rb → mouse_events/app.rb} +29 -27
- data/examples/mouse_events/app.rbs +7 -0
- data/examples/mouse_events/test_app.rb +53 -0
- data/examples/{popup_demo.rb → popup_demo/app.rb} +15 -17
- data/examples/popup_demo/app.rbs +7 -0
- data/examples/{test_popup_demo.rb → popup_demo/test_app.rb} +18 -26
- data/examples/quickstart_dsl/app.rb +36 -0
- data/examples/quickstart_dsl/app.rbs +7 -0
- data/examples/quickstart_dsl/test_app.rb +29 -0
- data/examples/quickstart_lifecycle/app.rb +39 -0
- data/examples/quickstart_lifecycle/app.rbs +7 -0
- data/examples/quickstart_lifecycle/test_app.rb +29 -0
- data/examples/ratatui_logo_demo/app.rb +79 -0
- data/examples/ratatui_logo_demo/app.rbs +7 -0
- data/examples/ratatui_logo_demo/test_app.rb +51 -0
- data/examples/ratatui_mascot_demo/app.rb +84 -0
- data/examples/ratatui_mascot_demo/app.rbs +7 -0
- data/examples/ratatui_mascot_demo/test_app.rb +47 -0
- data/examples/readme_usage/app.rb +29 -0
- data/examples/readme_usage/app.rbs +7 -0
- data/examples/readme_usage/test_app.rb +29 -0
- data/examples/rich_text/app.rb +141 -0
- data/examples/rich_text/app.rbs +7 -0
- data/examples/rich_text/test_app.rb +166 -0
- data/examples/scroll_text/app.rb +103 -0
- data/examples/scroll_text/app.rbs +7 -0
- data/examples/scroll_text/test_app.rb +110 -0
- data/examples/scrollbar_demo/app.rb +143 -0
- data/examples/scrollbar_demo/app.rbs +7 -0
- data/examples/scrollbar_demo/test_app.rb +77 -0
- data/examples/sparkline_demo/app.rb +240 -0
- data/examples/sparkline_demo/app.rbs +10 -0
- data/examples/sparkline_demo/test_app.rb +107 -0
- data/examples/table_flex/app.rb +65 -0
- data/examples/table_flex/app.rbs +7 -0
- data/examples/table_flex/test_app.rb +36 -0
- data/examples/table_select/app.rb +198 -0
- data/examples/table_select/app.rbs +7 -0
- data/examples/table_select/test_app.rb +180 -0
- data/examples/widget_style_colors/app.rb +104 -0
- data/examples/widget_style_colors/app.rbs +14 -0
- data/examples/widget_style_colors/test_app.rb +48 -0
- data/ext/ratatui_ruby/Cargo.lock +889 -115
- data/ext/ratatui_ruby/Cargo.toml +4 -3
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +7 -0
- data/ext/ratatui_ruby/src/events.rs +218 -229
- data/ext/ratatui_ruby/src/lib.rs +38 -10
- data/ext/ratatui_ruby/src/rendering.rs +90 -10
- data/ext/ratatui_ruby/src/style.rs +281 -98
- data/ext/ratatui_ruby/src/terminal.rs +119 -25
- data/ext/ratatui_ruby/src/text.rs +171 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +97 -24
- data/ext/ratatui_ruby/src/widgets/block.rs +31 -3
- data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
- data/ext/ratatui_ruby/src/widgets/canvas.rs +46 -29
- data/ext/ratatui_ruby/src/widgets/chart.rs +69 -27
- data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
- data/ext/ratatui_ruby/src/widgets/layout.rs +218 -15
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +91 -11
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +3 -2
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +29 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +44 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +59 -7
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +70 -6
- data/ext/ratatui_ruby/src/widgets/table.rs +173 -64
- data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
- data/lib/ratatui_ruby/cell.rb +166 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
- data/lib/ratatui_ruby/event/key.rb +211 -0
- data/lib/ratatui_ruby/event/mouse.rb +124 -0
- data/lib/ratatui_ruby/event/paste.rb +71 -0
- data/lib/ratatui_ruby/event/resize.rb +80 -0
- data/lib/ratatui_ruby/event.rb +79 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +27 -0
- data/lib/ratatui_ruby/schema/bar_chart.rb +228 -19
- data/lib/ratatui_ruby/schema/block.rb +186 -14
- data/lib/ratatui_ruby/schema/calendar.rb +74 -17
- data/lib/ratatui_ruby/schema/canvas.rb +215 -48
- data/lib/ratatui_ruby/schema/center.rb +49 -11
- data/lib/ratatui_ruby/schema/chart.rb +151 -41
- data/lib/ratatui_ruby/schema/clear.rb +41 -72
- data/lib/ratatui_ruby/schema/constraint.rb +82 -22
- data/lib/ratatui_ruby/schema/cursor.rb +27 -9
- data/lib/ratatui_ruby/schema/draw.rb +53 -0
- data/lib/ratatui_ruby/schema/gauge.rb +59 -15
- data/lib/ratatui_ruby/schema/layout.rb +95 -13
- data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
- data/lib/ratatui_ruby/schema/list.rb +93 -19
- data/lib/ratatui_ruby/schema/overlay.rb +34 -8
- data/lib/ratatui_ruby/schema/paragraph.rb +87 -30
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +25 -0
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +29 -0
- data/lib/ratatui_ruby/schema/rect.rb +64 -15
- data/lib/ratatui_ruby/schema/scrollbar.rb +132 -24
- data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
- data/lib/ratatui_ruby/schema/sparkline.rb +122 -15
- data/lib/ratatui_ruby/schema/style.rb +49 -21
- data/lib/ratatui_ruby/schema/table.rb +119 -21
- data/lib/ratatui_ruby/schema/tabs.rb +75 -13
- data/lib/ratatui_ruby/schema/text.rb +90 -0
- data/lib/ratatui_ruby/session.rb +146 -0
- data/lib/ratatui_ruby/test_helper.rb +156 -13
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +143 -23
- data/sig/ratatui_ruby/event.rbs +69 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -1
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
- data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
- data/sig/ratatui_ruby/schema/block.rbs +5 -4
- data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
- data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
- data/sig/ratatui_ruby/schema/center.rbs +3 -3
- data/sig/ratatui_ruby/schema/chart.rbs +8 -5
- data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
- data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
- data/sig/ratatui_ruby/schema/draw.rbs +23 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
- data/sig/ratatui_ruby/schema/layout.rbs +11 -1
- data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
- data/sig/ratatui_ruby/schema/list.rbs +5 -1
- data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
- data/{lib/ratatui_ruby/output.rb → sig/ratatui_ruby/schema/ratatui_logo.rbs} +3 -2
- data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
- data/sig/ratatui_ruby/schema/rect.rbs +2 -1
- data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
- data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
- data/sig/ratatui_ruby/schema/table.rbs +8 -1
- data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
- data/sig/ratatui_ruby/schema/text.rbs +22 -0
- data/tasks/resources/build.yml.erb +13 -11
- data/tasks/terminal_preview/app_screenshot.rb +35 -0
- data/tasks/terminal_preview/crash_report.rb +54 -0
- data/tasks/terminal_preview/example_app.rb +25 -0
- data/tasks/terminal_preview/launcher_script.rb +48 -0
- data/tasks/terminal_preview/preview_collection.rb +60 -0
- data/tasks/terminal_preview/preview_timing.rb +22 -0
- data/tasks/terminal_preview/safety_confirmation.rb +58 -0
- data/tasks/terminal_preview/saved_screenshot.rb +55 -0
- data/tasks/terminal_preview/system_appearance.rb +11 -0
- data/tasks/terminal_preview/terminal_window.rb +138 -0
- data/tasks/terminal_preview/window_id.rb +14 -0
- data/tasks/terminal_preview.rake +28 -0
- data/tasks/test.rake +1 -1
- metadata +174 -53
- data/doc/images/examples-analytics.rb.png +0 -0
- data/doc/images/examples-box_demo.rb.png +0 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-dashboard.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-login_form.rb.png +0 -0
- data/doc/images/examples-map_demo.rb.png +0 -0
- data/doc/images/examples-mouse_events.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-scrollbar_demo.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-system_monitor.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/examples/analytics.rb +0 -88
- data/examples/box_demo.rb +0 -71
- data/examples/calendar_demo.rb +0 -55
- data/examples/chart_demo.rb +0 -84
- data/examples/custom_widget.rb +0 -43
- data/examples/dashboard.rb +0 -72
- data/examples/list_styles.rb +0 -66
- data/examples/map_demo.rb +0 -58
- data/examples/quickstart_dsl.rb +0 -30
- data/examples/quickstart_lifecycle.rb +0 -40
- data/examples/readme_usage.rb +0 -21
- data/examples/scroll_text.rb +0 -74
- data/examples/scrollbar_demo.rb +0 -75
- data/examples/stock_ticker.rb +0 -93
- data/examples/system_monitor.rb +0 -94
- data/examples/table_select.rb +0 -70
- data/examples/test_analytics.rb +0 -65
- data/examples/test_box_demo.rb +0 -38
- data/examples/test_calendar_demo.rb +0 -66
- data/examples/test_dashboard.rb +0 -38
- data/examples/test_list_styles.rb +0 -61
- data/examples/test_login_form.rb +0 -63
- data/examples/test_map_demo.rb +0 -100
- data/examples/test_scroll_text.rb +0 -130
- data/examples/test_stock_ticker.rb +0 -39
- data/examples/test_system_monitor.rb +0 -40
- data/examples/test_table_select.rb +0 -37
- data/ext/ratatui_ruby/src/buffer.rs +0 -54
- data/lib/ratatui_ruby/dsl.rb +0 -64
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestListDemoApp < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = ListDemoApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_render_initial_state
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
content = buffer_content
|
|
25
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
26
|
+
assert content.any? { |line| line.include?("Large List") }
|
|
27
|
+
assert content.any? { |line| line.include?("Item 1") }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_navigate_down
|
|
32
|
+
with_test_terminal do
|
|
33
|
+
inject_keys(:down, :q)
|
|
34
|
+
@app.run
|
|
35
|
+
|
|
36
|
+
content = buffer_content
|
|
37
|
+
# Initial large list, down selects first item (Item 1)
|
|
38
|
+
assert content.any? { |line| line.include?(">> Item 1") }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_navigate_up_wraps
|
|
43
|
+
with_test_terminal do
|
|
44
|
+
inject_keys(:up, :q)
|
|
45
|
+
@app.run
|
|
46
|
+
|
|
47
|
+
content = buffer_content
|
|
48
|
+
# Should wrap to last item of Large List (Item 200)
|
|
49
|
+
assert content.any? { |line| line.include?(">> Item 200") }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_toggle_selection_on
|
|
54
|
+
with_test_terminal do
|
|
55
|
+
inject_keys(:x, :q)
|
|
56
|
+
@app.run
|
|
57
|
+
|
|
58
|
+
content = buffer_content
|
|
59
|
+
# Selects index 0 (Item 1)
|
|
60
|
+
assert content.any? { |line| line.include?(">> Item 1") }
|
|
61
|
+
assert content.any? { |line| line.include?("Selection: 0") }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_toggle_selection_off
|
|
66
|
+
with_test_terminal do
|
|
67
|
+
inject_keys(:x, :x, :q)
|
|
68
|
+
@app.run
|
|
69
|
+
|
|
70
|
+
content = buffer_content
|
|
71
|
+
refute content.any? { |line| line.include?(">> ") && line.include?("Item 1") }
|
|
72
|
+
assert content.any? { |line| line.include?("Selection: none") }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_cycle_item_set
|
|
77
|
+
with_test_terminal do
|
|
78
|
+
inject_keys(:i, :q)
|
|
79
|
+
@app.run
|
|
80
|
+
|
|
81
|
+
content = buffer_content
|
|
82
|
+
# Cycles to next set: Colors
|
|
83
|
+
assert content.any? { |line| line.include?("Colors") }
|
|
84
|
+
assert content.any? { |line| line.include?("Red") }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_cycle_item_set_multiple_times
|
|
89
|
+
with_test_terminal do
|
|
90
|
+
# 0=Large, 1=Colors, 2=Fruits, 3=Programming
|
|
91
|
+
inject_keys(:i, :i, :i, :q)
|
|
92
|
+
@app.run
|
|
93
|
+
|
|
94
|
+
content = buffer_content
|
|
95
|
+
assert content.any? { |line| line.include?("Programming") }
|
|
96
|
+
assert content.any? { |line| line.include?("Ruby") }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_cycle_highlight_style
|
|
101
|
+
with_test_terminal do
|
|
102
|
+
inject_keys(:h, :q)
|
|
103
|
+
@app.run
|
|
104
|
+
|
|
105
|
+
content = buffer_content
|
|
106
|
+
assert content.any? { |line| line.include?("Yellow on Black") }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_cycle_highlight_symbol
|
|
111
|
+
with_test_terminal do
|
|
112
|
+
inject_keys(:x, :y, :q)
|
|
113
|
+
@app.run
|
|
114
|
+
|
|
115
|
+
content = buffer_content
|
|
116
|
+
assert content.any? { |line| line.include?("▶") }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_cycle_direction
|
|
121
|
+
with_test_terminal do
|
|
122
|
+
inject_keys(:d, :q)
|
|
123
|
+
@app.run
|
|
124
|
+
|
|
125
|
+
content = buffer_content
|
|
126
|
+
assert content.any? { |line| line.include?("Bottom to Top") }
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_cycle_spacing
|
|
131
|
+
with_test_terminal do
|
|
132
|
+
inject_keys(:s, :q)
|
|
133
|
+
@app.run
|
|
134
|
+
|
|
135
|
+
content = buffer_content
|
|
136
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_spacing_always_shows_column
|
|
141
|
+
with_test_terminal do
|
|
142
|
+
# Need to enable always spacing (:s) on Item list
|
|
143
|
+
inject_keys(:s, :q)
|
|
144
|
+
@app.run
|
|
145
|
+
|
|
146
|
+
content = buffer_content
|
|
147
|
+
# With :always spacing, unselected items are indented
|
|
148
|
+
assert content.any? { |line| line.include?(" Item 1") }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def test_cycle_base_style
|
|
153
|
+
with_test_terminal do
|
|
154
|
+
inject_keys(:b, :q)
|
|
155
|
+
@app.run
|
|
156
|
+
|
|
157
|
+
content = buffer_content
|
|
158
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_cycle_repeat_symbol
|
|
163
|
+
with_test_terminal do
|
|
164
|
+
inject_keys(:r, :q)
|
|
165
|
+
@app.run
|
|
166
|
+
|
|
167
|
+
content = buffer_content
|
|
168
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_selection_resets_on_item_set_change
|
|
173
|
+
with_test_terminal do
|
|
174
|
+
inject_keys(:x, :down, :i, :q)
|
|
175
|
+
@app.run
|
|
176
|
+
|
|
177
|
+
content = buffer_content
|
|
178
|
+
# After changing item set to Colors, selection should reset
|
|
179
|
+
assert content.any? { |line| line.include?("Selection: none") }
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def test_quit_with_ctrl_c
|
|
184
|
+
with_test_terminal do
|
|
185
|
+
inject_keys("c", :q)
|
|
186
|
+
@app.run
|
|
187
|
+
|
|
188
|
+
content = buffer_content
|
|
189
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_demo_title_always_visible
|
|
194
|
+
with_test_terminal do
|
|
195
|
+
inject_keys(:i, :h, :y, :d, :s, :b, :r, :q)
|
|
196
|
+
@app.run
|
|
197
|
+
|
|
198
|
+
content = buffer_content
|
|
199
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def test_cycle_scroll_padding
|
|
204
|
+
with_test_terminal do
|
|
205
|
+
inject_keys(:p, :q)
|
|
206
|
+
@app.run
|
|
207
|
+
|
|
208
|
+
content = buffer_content
|
|
209
|
+
# 0=None, 1=1 item
|
|
210
|
+
assert content.any? { |line| line.include?("Scroll Padding (1 item)") }
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_scroll_padding_changes_display
|
|
215
|
+
with_test_terminal do
|
|
216
|
+
# Switch to Colors (i), Toggle select (x), scroll down, toggle padding (p)
|
|
217
|
+
inject_keys(:i, :x, :down, :p, :q)
|
|
218
|
+
@app.run
|
|
219
|
+
|
|
220
|
+
content = buffer_content
|
|
221
|
+
assert content.any? { |line| line.include?("Colors") }
|
|
222
|
+
# Selected index 1 (Orange) of Colors
|
|
223
|
+
assert content.any? { |line| line.include?(">> Orange") }
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def test_multiple_navigation_and_options
|
|
228
|
+
with_test_terminal do
|
|
229
|
+
# Interactive usage smoke test
|
|
230
|
+
inject_keys(:down, :h, :down, :y, :up, :b, :q)
|
|
231
|
+
@app.run
|
|
232
|
+
|
|
233
|
+
content = buffer_content
|
|
234
|
+
assert content.any? { |line| line.include?("List Widget Demo") }
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
|
|
9
|
+
# Styled List Example
|
|
10
|
+
# Demonstrates advanced styling options for the List widget.
|
|
11
|
+
class ListStylesApp
|
|
12
|
+
attr_reader :selected_index, :highlight_spacing
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@items = ["Item 1", "Item 2", "Item 3"]
|
|
16
|
+
@selected_index = nil
|
|
17
|
+
|
|
18
|
+
@directions = [
|
|
19
|
+
{ name: "Top to Bottom", direction: :top_to_bottom },
|
|
20
|
+
{ name: "Bottom to Top", direction: :bottom_to_top }
|
|
21
|
+
]
|
|
22
|
+
@direction_index = 0
|
|
23
|
+
|
|
24
|
+
@highlight_spacings = [
|
|
25
|
+
{ name: "When Selected", spacing: :when_selected },
|
|
26
|
+
{ name: "Always", spacing: :always },
|
|
27
|
+
{ name: "Never", spacing: :never }
|
|
28
|
+
]
|
|
29
|
+
@highlight_spacing_index = 0
|
|
30
|
+
|
|
31
|
+
@repeat_modes = [
|
|
32
|
+
{ name: "Off", repeat: false },
|
|
33
|
+
{ name: "On", repeat: true }
|
|
34
|
+
]
|
|
35
|
+
@repeat_index = 0
|
|
36
|
+
|
|
37
|
+
@hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run
|
|
41
|
+
RatatuiRuby.run do
|
|
42
|
+
loop do
|
|
43
|
+
render
|
|
44
|
+
break if handle_input == :quit
|
|
45
|
+
sleep 0.05
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def render
|
|
53
|
+
selection_label = @selected_index.nil? ? "none" : @selected_index.to_s
|
|
54
|
+
direction_config = @directions[@direction_index]
|
|
55
|
+
spacing_config = @highlight_spacings[@highlight_spacing_index]
|
|
56
|
+
repeat_config = @repeat_modes[@repeat_index]
|
|
57
|
+
|
|
58
|
+
# Main content
|
|
59
|
+
main_list = RatatuiRuby::List.new(
|
|
60
|
+
items: @items,
|
|
61
|
+
selected_index: @selected_index,
|
|
62
|
+
style: RatatuiRuby::Style.new(fg: :white, bg: :black),
|
|
63
|
+
highlight_style: RatatuiRuby::Style.new(fg: :blue, bg: :white, modifiers: [:bold]),
|
|
64
|
+
highlight_symbol: ">> ",
|
|
65
|
+
repeat_highlight_symbol: repeat_config[:repeat],
|
|
66
|
+
highlight_spacing: spacing_config[:spacing],
|
|
67
|
+
direction: direction_config[:direction],
|
|
68
|
+
block: RatatuiRuby::Block.new(
|
|
69
|
+
title: "Items",
|
|
70
|
+
borders: [:all]
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Bottom control panel
|
|
75
|
+
control_panel = RatatuiRuby::Block.new(
|
|
76
|
+
title: "Controls",
|
|
77
|
+
borders: [:all],
|
|
78
|
+
children: [
|
|
79
|
+
RatatuiRuby::Paragraph.new(
|
|
80
|
+
text: [
|
|
81
|
+
RatatuiRuby::Text::Line.new(spans: [
|
|
82
|
+
RatatuiRuby::Text::Span.new(content: "↑/↓", style: @hotkey_style),
|
|
83
|
+
RatatuiRuby::Text::Span.new(content: ": Select (#{selection_label}) "),
|
|
84
|
+
RatatuiRuby::Text::Span.new(content: "x", style: @hotkey_style),
|
|
85
|
+
RatatuiRuby::Text::Span.new(content: ": Toggle Selection "),
|
|
86
|
+
RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
|
|
87
|
+
RatatuiRuby::Text::Span.new(content: ": Quit")
|
|
88
|
+
]),
|
|
89
|
+
RatatuiRuby::Text::Line.new(spans: [
|
|
90
|
+
RatatuiRuby::Text::Span.new(content: "d", style: @hotkey_style),
|
|
91
|
+
RatatuiRuby::Text::Span.new(content: ": Direction (#{direction_config[:name]}) "),
|
|
92
|
+
RatatuiRuby::Text::Span.new(content: "s", style: @hotkey_style),
|
|
93
|
+
RatatuiRuby::Text::Span.new(content: ": Spacing (#{spacing_config[:name]})")
|
|
94
|
+
]),
|
|
95
|
+
RatatuiRuby::Text::Line.new(spans: [
|
|
96
|
+
RatatuiRuby::Text::Span.new(content: "r", style: @hotkey_style),
|
|
97
|
+
RatatuiRuby::Text::Span.new(content: ": Repeat Symbol (#{repeat_config[:name]})")
|
|
98
|
+
])
|
|
99
|
+
]
|
|
100
|
+
)
|
|
101
|
+
]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Vertical Layout
|
|
105
|
+
layout = RatatuiRuby::Layout.new(
|
|
106
|
+
direction: :vertical,
|
|
107
|
+
constraints: [
|
|
108
|
+
RatatuiRuby::Constraint.fill(1),
|
|
109
|
+
RatatuiRuby::Constraint.length(5),
|
|
110
|
+
],
|
|
111
|
+
children: [main_list, control_panel]
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
RatatuiRuby.draw(layout)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def handle_input
|
|
118
|
+
case RatatuiRuby.poll_event
|
|
119
|
+
in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
|
|
120
|
+
:quit
|
|
121
|
+
in type: :key, code: "up"
|
|
122
|
+
@selected_index = (@selected_index || 0) - 1
|
|
123
|
+
@selected_index = @items.size - 1 if @selected_index.negative?
|
|
124
|
+
in type: :key, code: "down"
|
|
125
|
+
@selected_index = ((@selected_index || -1) + 1) % @items.size
|
|
126
|
+
in type: :key, code: "d"
|
|
127
|
+
@direction_index = (@direction_index + 1) % @directions.size
|
|
128
|
+
in type: :key, code: "s"
|
|
129
|
+
@highlight_spacing_index = (@highlight_spacing_index + 1) % @highlight_spacings.size
|
|
130
|
+
in type: :key, code: "r"
|
|
131
|
+
@repeat_index = (@repeat_index + 1) % @repeat_modes.size
|
|
132
|
+
in type: :key, code: "x"
|
|
133
|
+
@selected_index = @selected_index.nil? ? 0 : nil
|
|
134
|
+
else
|
|
135
|
+
nil
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
ListStylesApp.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestListStylesExample < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = ListStylesApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_render_initial_state_no_selection
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
# Default is :when_selected with no selection, so no highlight symbol column
|
|
25
|
+
content = buffer_content
|
|
26
|
+
assert content.any? { |line| line.include?("Item 1") }
|
|
27
|
+
assert content.any? { |line| line.include?("Item 2") }
|
|
28
|
+
refute content.any? { |line| line.include?(">>") }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_toggle_selection_on
|
|
33
|
+
with_test_terminal do
|
|
34
|
+
# Press x to toggle on, then quit
|
|
35
|
+
inject_keys(:x, :q)
|
|
36
|
+
@app.run
|
|
37
|
+
|
|
38
|
+
content = buffer_content
|
|
39
|
+
assert content.any? { |line| line.include?(">> Item 1") }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_toggle_selection_off
|
|
44
|
+
with_test_terminal do
|
|
45
|
+
# Press x to toggle on, x again to toggle off, then quit
|
|
46
|
+
inject_keys(:x, :x, :q)
|
|
47
|
+
@app.run
|
|
48
|
+
|
|
49
|
+
content = buffer_content
|
|
50
|
+
refute content.any? { |line| line.include?(">>") }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_navigation_selects_and_moves
|
|
55
|
+
with_test_terminal do
|
|
56
|
+
inject_keys(:down, :q)
|
|
57
|
+
@app.run
|
|
58
|
+
|
|
59
|
+
content = buffer_content
|
|
60
|
+
assert content.any? { |line| line.include?(">> Item 1") }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_navigation_down_twice
|
|
65
|
+
with_test_terminal do
|
|
66
|
+
inject_keys(:down, :down, :q)
|
|
67
|
+
@app.run
|
|
68
|
+
|
|
69
|
+
content = buffer_content
|
|
70
|
+
assert content.any? { |line| line.include?(">> Item 2") }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_quit
|
|
75
|
+
with_test_terminal do
|
|
76
|
+
inject_key(:q)
|
|
77
|
+
@app.run
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_toggle_highlight_spacing_to_always
|
|
82
|
+
with_test_terminal do
|
|
83
|
+
# 's' cycles: when_selected -> always -> never
|
|
84
|
+
inject_keys(:s, :q)
|
|
85
|
+
@app.run
|
|
86
|
+
|
|
87
|
+
content = buffer_content
|
|
88
|
+
assert content.any? { |line| line.include?("Always") }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_toggle_highlight_spacing_to_never
|
|
93
|
+
with_test_terminal do
|
|
94
|
+
inject_keys(:s, :s, :q)
|
|
95
|
+
@app.run
|
|
96
|
+
|
|
97
|
+
content = buffer_content
|
|
98
|
+
assert content.any? { |line| line.include?("Never") }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_toggle_highlight_spacing_back_to_when_selected
|
|
103
|
+
with_test_terminal do
|
|
104
|
+
inject_keys(:s, :s, :s, :q)
|
|
105
|
+
@app.run
|
|
106
|
+
|
|
107
|
+
content = buffer_content
|
|
108
|
+
assert content.any? { |line| line.include?("When Selected") }
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_direction_cycling
|
|
113
|
+
with_test_terminal do
|
|
114
|
+
inject_keys(:d, :q)
|
|
115
|
+
@app.run
|
|
116
|
+
|
|
117
|
+
content = buffer_content
|
|
118
|
+
assert content.any? { |line| line.include?("Bottom to Top") }
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_spacing_always_shows_column_without_selection
|
|
123
|
+
with_test_terminal do
|
|
124
|
+
# Set spacing to :always
|
|
125
|
+
inject_keys(:s, :q)
|
|
126
|
+
@app.run
|
|
127
|
+
|
|
128
|
+
content = buffer_content
|
|
129
|
+
# With :always, spacing column is shown even without selection
|
|
130
|
+
assert content.any? { |line| line.include?(" Item 1") }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_repeat_highlight_symbol_toggle
|
|
135
|
+
with_test_terminal do
|
|
136
|
+
# Press r to toggle repeat mode, then quit
|
|
137
|
+
inject_keys(:r, :q)
|
|
138
|
+
@app.run
|
|
139
|
+
|
|
140
|
+
content = buffer_content
|
|
141
|
+
assert content.any? { |line| line.include?("Repeat Symbol") }
|
|
142
|
+
assert content.any? { |line| line.include?("On") }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_repeat_highlight_symbol_cycles_back
|
|
147
|
+
with_test_terminal do
|
|
148
|
+
# Press r twice to cycle back to Off
|
|
149
|
+
inject_keys(:r, :r, :q)
|
|
150
|
+
@app.run
|
|
151
|
+
|
|
152
|
+
content = buffer_content
|
|
153
|
+
assert content.any? { |line| line.include?("Repeat Symbol") }
|
|
154
|
+
assert content.any? { |line| line.include?("Off") }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
7
|
require "ratatui_ruby"
|
|
8
8
|
|
|
9
9
|
class LoginFormApp
|
|
@@ -16,17 +16,16 @@ class LoginFormApp
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def run
|
|
19
|
-
RatatuiRuby.
|
|
20
|
-
begin
|
|
19
|
+
RatatuiRuby.run do
|
|
21
20
|
loop do
|
|
22
21
|
render
|
|
23
22
|
break if handle_input == :quit
|
|
24
23
|
end
|
|
25
|
-
ensure
|
|
26
|
-
RatatuiRuby.restore_terminal
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
26
|
|
|
27
|
+
private
|
|
28
|
+
|
|
30
29
|
def render
|
|
31
30
|
# 1. Base Layer Construction
|
|
32
31
|
# We want a cursor relative to the paragraph.
|
|
@@ -44,7 +43,7 @@ class LoginFormApp
|
|
|
44
43
|
RatatuiRuby::Paragraph.new(
|
|
45
44
|
text: "#{PREFIX}#{@username}#{SUFFIX}",
|
|
46
45
|
block: RatatuiRuby::Block.new(borders: :all, title: "Login Form"),
|
|
47
|
-
|
|
46
|
+
alignment: :left
|
|
48
47
|
),
|
|
49
48
|
RatatuiRuby::Cursor.new(x: cursor_x, y: cursor_y),
|
|
50
49
|
])
|
|
@@ -63,7 +62,7 @@ class LoginFormApp
|
|
|
63
62
|
text: "Login Successful!\nPress 'q' to quit.",
|
|
64
63
|
style: RatatuiRuby::Style.new(fg: :green, bg: :black),
|
|
65
64
|
block: RatatuiRuby::Block.new(borders: :all),
|
|
66
|
-
|
|
65
|
+
alignment: :center,
|
|
67
66
|
wrap: true
|
|
68
67
|
),
|
|
69
68
|
width_percent: 30,
|
|
@@ -85,16 +84,13 @@ class LoginFormApp
|
|
|
85
84
|
event = RatatuiRuby.poll_event
|
|
86
85
|
return unless event
|
|
87
86
|
|
|
88
|
-
if event
|
|
87
|
+
if event.key?
|
|
89
88
|
if @show_popup
|
|
90
|
-
|
|
91
|
-
# "The Center widget contains a Green Box saying 'Login Successful! Press q.'"
|
|
92
|
-
if event[:code] == "q"
|
|
93
|
-
:quit
|
|
94
|
-
end
|
|
89
|
+
return :quit if event == "q" || event == :ctrl_c
|
|
95
90
|
else
|
|
96
91
|
# Login Form Input
|
|
97
|
-
|
|
92
|
+
return :quit if event == :ctrl_c
|
|
93
|
+
case event.code
|
|
98
94
|
when "enter"
|
|
99
95
|
@show_popup = true
|
|
100
96
|
when "backspace"
|
|
@@ -103,8 +99,8 @@ class LoginFormApp
|
|
|
103
99
|
:quit
|
|
104
100
|
else
|
|
105
101
|
# Simple text input
|
|
106
|
-
if event
|
|
107
|
-
@username += event
|
|
102
|
+
if event.text? && !event.ctrl? && !event.alt?
|
|
103
|
+
@username += event.code
|
|
108
104
|
end
|
|
109
105
|
end
|
|
110
106
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestLoginForm < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = LoginFormApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_render_initial_state
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
# Queue quit
|
|
22
|
+
inject_keys(:esc)
|
|
23
|
+
|
|
24
|
+
@app.run
|
|
25
|
+
|
|
26
|
+
assert buffer_content.any? { |line| line.include?("Enter Username:") }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_input_handling
|
|
31
|
+
with_test_terminal do
|
|
32
|
+
# Type 'a' then quit
|
|
33
|
+
inject_keys("a", :esc)
|
|
34
|
+
|
|
35
|
+
@app.run
|
|
36
|
+
|
|
37
|
+
assert buffer_content.any? { |line| line.include?("Enter Username: [ a ]") }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_popup_flow
|
|
42
|
+
with_test_terminal do
|
|
43
|
+
# Enter username 'user', press Enter, then quit
|
|
44
|
+
inject_keys("u", "s", "e", "r", :enter, :q)
|
|
45
|
+
|
|
46
|
+
@app.run
|
|
47
|
+
|
|
48
|
+
assert buffer_content.any? { |line| line.include?("Successful!") }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|