Skip to content

Commit 1bf264a

Browse files
committed
test(ui): add UI snapshot tests for the TUI components
1 parent b93feb9 commit 1bf264a

26 files changed

Lines changed: 587 additions & 13 deletions

Cargo.lock

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ vergen-gix = { version = "9.1.0", features = ["build", "cargo"] }
7575
[dev-dependencies]
7676
criterion = { version = "0.5.1", features = ["html_reports"] }
7777
fake = "4.4.0"
78+
insta = "1.40"
7879

7980
[[bench]]
8081
name = "ui_hotspots"

src/ui/components/issue_detail.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub struct PrSummary {
9999
}
100100

101101
pub struct IssuePreview {
102-
current: Option<IssuePreviewSeed>,
102+
pub current: Option<IssuePreviewSeed>,
103103
action_tx: Option<tokio::sync::mpsc::Sender<Action>>,
104104
area: Rect,
105105
}

src/ui/components/label_list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,3 +1262,4 @@ impl HasFocus for LabelList {
12621262
self.state.focus()
12631263
}
12641264
}
1265+

src/ui/components/search_bar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ pub const HELP: &[HelpElementKind] = &[
4141
];
4242

4343
pub struct TextSearch {
44-
search_state: rat_widget::text_input::TextInputState,
45-
label_state: rat_widget::text_input::TextInputState,
44+
pub search_state: rat_widget::text_input::TextInputState,
45+
pub label_state: rat_widget::text_input::TextInputState,
4646
cstate: ChoiceState,
4747
state: State,
4848
action_tx: Option<tokio::sync::mpsc::Sender<Action>>,

src/ui/components/status_bar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use ratatui::widgets::Widget;
55
use ratatui_macros::{line, span};
66
use std::sync::atomic::Ordering;
77

8-
use crate::ui::components::DumbComponent;
98
use crate::ui::components::issue_list::LOADED_ISSUE_COUNT;
10-
use crate::ui::{AppState, layout::Layout};
9+
use crate::ui::components::DumbComponent;
10+
use crate::ui::{layout::Layout, AppState};
1111

1212
pub struct StatusBar {
1313
repo_label: String,

src/ui/testing.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,29 @@ use fake::{
1010
};
1111
use octocrab::models::{Event as IssueEvent, IssueState};
1212

13-
use crate::{
14-
bench_support::{issue_body_fixture, markdown_fixture},
15-
ui::{
16-
components::{
17-
issue_conversation::{CommentView, IssueConversationSeed, TimelineEventView},
18-
issue_detail::IssuePreviewSeed,
19-
},
20-
issue_data::{AuthorId, IssueId, UiIssue, UiIssuePool},
13+
#[cfg(feature = "benches")]
14+
use crate::bench_support::{issue_body_fixture, markdown_fixture};
15+
16+
#[cfg(not(feature = "benches"))]
17+
mod bench_support {
18+
pub fn issue_body_fixture(_seed: u64) -> String {
19+
String::new()
20+
}
21+
pub fn markdown_fixture(_seed: u64) -> String {
22+
String::new()
23+
}
24+
}
25+
26+
#[allow(unused_imports)]
27+
#[cfg(not(feature = "benches"))]
28+
use bench_support::{issue_body_fixture, markdown_fixture};
29+
30+
use crate::ui::{
31+
components::{
32+
issue_conversation::{CommentView, IssueConversationSeed, TimelineEventView},
33+
issue_detail::IssuePreviewSeed,
2134
},
35+
issue_data::{AuthorId, IssueId, UiIssue, UiIssuePool},
2236
};
2337

2438
#[derive(Debug, Clone, Copy)]

tests/help.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
mod support;
2+
use crate::support::buffer_to_string;
3+
use gitv_tui::ui::components::help::{HelpComponent, HelpElementKind};
4+
use insta::assert_snapshot;
5+
use ratatui::buffer::Buffer;
6+
use ratatui::layout::Rect;
7+
use ratatui::widgets::{Block, Widget};
8+
9+
fn render_help_component(elements: &[HelpElementKind], width: u16, height: u16) -> String {
10+
let area = Rect::new(0, 0, width, height);
11+
let mut buf = Buffer::empty(area);
12+
let component = HelpComponent::new(elements).set_constraint(50).block(
13+
Block::bordered()
14+
.title("Help")
15+
.padding(ratatui::widgets::Padding::horizontal(2))
16+
.border_type(ratatui::widgets::BorderType::Rounded),
17+
);
18+
component.render(area, &mut buf);
19+
buffer_to_string(&buf)
20+
}
21+
22+
#[test]
23+
fn help_elements_keybinds_only() {
24+
let elements = &[
25+
HelpElementKind::Keybind("Up", "navigate up"),
26+
HelpElementKind::Keybind("Down", "navigate down"),
27+
HelpElementKind::Keybind("Enter", "select item"),
28+
];
29+
let result = render_help_component(elements, 60, 20);
30+
assert_snapshot!(result);
31+
}
32+
33+
#[test]
34+
fn help_elements_text_wrapping() {
35+
let elements = &[HelpElementKind::Text(
36+
"This is a very long description that should wrap properly across multiple lines when rendered in the help component.",
37+
)];
38+
let result = render_help_component(elements, 50, 15);
39+
assert_snapshot!(result);
40+
}
41+
42+
#[test]
43+
fn help_elements_mixed_content() {
44+
let elements = &[
45+
HelpElementKind::Text("Global Help"),
46+
HelpElementKind::Keybind("q", "quit application"),
47+
HelpElementKind::Text(""),
48+
HelpElementKind::Keybind("?", "toggle this help"),
49+
HelpElementKind::Keybind("Esc", "close dialog"),
50+
];
51+
let result = render_help_component(elements, 55, 20);
52+
assert_snapshot!(result);
53+
}
54+
55+
#[test]
56+
fn help_component_empty() {
57+
let elements: &[HelpElementKind] = &[];
58+
let result = render_help_component(elements, 40, 10);
59+
assert_snapshot!(result);
60+
}

tests/issue_preview.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use std::sync::Arc;
2+
3+
mod support;
4+
5+
use crate::support::buffer_to_string;
6+
use gitv_tui::ui::AppState;
7+
use gitv_tui::ui::components::issue_detail::{IssuePreview, IssuePreviewSeed};
8+
use gitv_tui::ui::layout::Layout;
9+
use insta::assert_snapshot;
10+
use octocrab::models::IssueState;
11+
use ratatui::buffer::Buffer;
12+
use ratatui::layout::Rect;
13+
14+
fn render_issue_preview(seed: Option<IssuePreviewSeed>) -> String {
15+
let area = Rect::new(0, 0, 40, 20);
16+
let layout = Layout::new(area);
17+
let mut buf = Buffer::empty(area);
18+
19+
let mut preview = IssuePreview::new(AppState::new(
20+
"owner".to_string(),
21+
"repo".to_string(),
22+
"user".to_string(),
23+
));
24+
25+
if let Some(s) = seed {
26+
preview.current = Some(s);
27+
}
28+
29+
preview.render(layout, &mut buf);
30+
buffer_to_string(&buf)
31+
}
32+
33+
#[test]
34+
fn issue_preview_open_issue() {
35+
let seed = IssuePreviewSeed {
36+
number: 42,
37+
state: IssueState::Open,
38+
author: Arc::from("johndoe"),
39+
created_at: Arc::from("2024-01-15 10:30"),
40+
updated_at: Arc::from("2024-01-16 14:45"),
41+
comments: 5,
42+
assignees: vec![Arc::from("alice"), Arc::from("bob")],
43+
milestone: Some(Arc::from("v1.0")),
44+
is_pull_request: false,
45+
pull_request_url: None,
46+
};
47+
let result = render_issue_preview(Some(seed));
48+
assert_snapshot!(result);
49+
}
50+
51+
#[test]
52+
fn issue_preview_closed_issue() {
53+
let seed = IssuePreviewSeed {
54+
number: 123,
55+
state: IssueState::Closed,
56+
author: Arc::from("janedoe"),
57+
created_at: Arc::from("2023-12-01 09:00"),
58+
updated_at: Arc::from("2023-12-05 16:30"),
59+
comments: 12,
60+
assignees: vec![Arc::from("charlie")],
61+
milestone: None,
62+
is_pull_request: false,
63+
pull_request_url: None,
64+
};
65+
let result = render_issue_preview(Some(seed));
66+
assert_snapshot!(result);
67+
}
68+
69+
#[test]
70+
fn issue_preview_pull_request() {
71+
let seed = IssuePreviewSeed {
72+
number: 456,
73+
state: IssueState::Open,
74+
author: Arc::from("devuser"),
75+
created_at: Arc::from("2024-02-01 11:00"),
76+
updated_at: Arc::from("2024-02-02 09:15"),
77+
comments: 8,
78+
assignees: vec![Arc::from("reviewer1"), Arc::from("reviewer2")],
79+
milestone: Some(Arc::from("Sprint 5")),
80+
is_pull_request: true,
81+
pull_request_url: Some(Arc::from("https://github.com/owner/repo/pull/456")),
82+
};
83+
let result = render_issue_preview(Some(seed));
84+
assert_snapshot!(result);
85+
}
86+
87+
#[test]
88+
fn issue_preview_no_selection() {
89+
let result = render_issue_preview(None);
90+
assert_snapshot!(result);
91+
}
92+
93+
#[test]
94+
fn issue_preview_many_assignees() {
95+
let seed = IssuePreviewSeed {
96+
number: 789,
97+
state: IssueState::Open,
98+
author: Arc::from("teamlead"),
99+
created_at: Arc::from("2024-03-01 08:00"),
100+
updated_at: Arc::from("2024-03-02 10:00"),
101+
comments: 3,
102+
assignees: vec![
103+
Arc::from("dev1"),
104+
Arc::from("dev2"),
105+
Arc::from("dev3"),
106+
Arc::from("dev4"),
107+
Arc::from("dev5"),
108+
],
109+
milestone: Some(Arc::from("v2.0")),
110+
is_pull_request: false,
111+
pull_request_url: None,
112+
};
113+
let result = render_issue_preview(Some(seed));
114+
assert_snapshot!(result);
115+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
source: tests/help.rs
3+
expression: result
4+
---
5+
6+
7+
8+
9+
10+
Help──────────────╮
11+
╰──────────────────╯

0 commit comments

Comments
 (0)