1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Tests for progressive rendering in `wt list`
//!
//! These tests capture multiple snapshots of the output as it renders,
//! verifying that the table structure appears first and data fills in progressively.
#![cfg(all(unix, feature = "shell-integration-tests"))]
use crate::common::progressive_output::{ProgressiveCaptureOptions, capture_progressive_output};
use crate::common::{TestRepo, repo};
use rstest::rstest;
/// Tests progressive rendering with multiple worktrees.
/// Verifies: headers appear immediately, dots decrease over time, all worktrees visible.
/// (Consolidates previous tests: rendering_basic, dots_decrease, many_worktrees)
#[rstest]
fn test_list_progressive_rendering(mut repo: TestRepo) {
// Create many worktrees to ensure rendering takes time
for i in 1..=10 {
repo.add_worktree(&format!("branch-{:02}", i));
}
let output = capture_progressive_output(
&repo,
"list",
&["--full", "--branches"],
ProgressiveCaptureOptions::with_byte_interval(500),
);
// Basic assertions
assert_eq!(output.exit_code, 0);
assert!(
output.stages.len() >= 3,
"Should capture at least 3 stages with many worktrees, got {}",
output.stages.len()
);
// Verify progressive filling: dots should decrease over time
output.verify_progressive_filling().unwrap();
// Verify table header appears in initial output
let initial = output.initial().visible_text();
assert!(
initial.contains("Branch"),
"Table header should appear immediately"
);
assert!(
initial.contains("Status"),
"Status column header should appear immediately"
);
// Verify final output has all worktrees
let final_output = output.final_output();
for i in 1..=10 {
assert!(
final_output.contains(&format!("branch-{:02}", i)),
"Final output should contain branch-{:02}",
i
);
}
}
/// Tests progressive output capture API: timestamps and snapshot_at.
/// (Consolidates previous tests: timing, snapshot_at)
#[rstest]
fn test_list_progressive_api(mut repo: TestRepo) {
repo.add_worktree("feature");
let output = capture_progressive_output(
&repo,
"list",
&[],
ProgressiveCaptureOptions::with_byte_interval(600),
);
// Verify timestamps are monotonically increasing
for i in 1..output.stages.len() {
assert!(
output.stages[i].timestamp >= output.stages[i - 1].timestamp,
"Timestamps should increase monotonically"
);
}
// Test snapshot_at API
let snapshot = output.snapshot_at(std::time::Duration::from_millis(100));
assert!(
!snapshot.visible_text().is_empty(),
"Snapshot should have content"
);
assert!(
snapshot.timestamp < output.total_duration,
"Snapshot should be before end"
);
}
/// Tests overflow mode: when worktrees exceed terminal height, the skeleton shows a subset,
/// then finalize erases and prints the complete table (scrolls naturally).
#[rstest]
fn test_list_progressive_overflow(mut repo: TestRepo) {
// Create enough worktrees to overflow a 10-row terminal.
// With height=10: visible_rows = 10 - 4 (header + spacer + footer + cursor) = 6
// 10 worktrees + main = 11 rows, well above the 6-row limit.
for i in 1..=10 {
repo.add_worktree(&format!("overflow-{:02}", i));
}
let mut opts = ProgressiveCaptureOptions::with_byte_interval(500);
opts.terminal_size = (10, 150); // Short terminal triggers overflow
let output = capture_progressive_output(&repo, "list", &["--full", "--branches"], opts);
assert_eq!(output.exit_code, 0);
// The overflow finalize path erases the skeleton and prints the complete table,
// which scrolls naturally. The vt100 parser (10 rows, no scrollback) only captures
// the visible tail. Verify: the footer and later branches are visible, confirming
// the overflow finalize path executed and printed the full table.
let final_text = output.final_output();
// Footer should be visible at the bottom
assert!(
final_text.contains("Showing"),
"Footer should be visible after overflow finalize.\nFinal output:\n{final_text}"
);
// Later branches should be visible (earlier ones scrolled off the 10-row viewport)
assert!(
final_text.contains("overflow-10"),
"Last branch should be visible.\nFinal output:\n{final_text}"
);
// No placeholder dots should remain — finalize printed real data
assert!(
!final_text.contains('⋯'),
"No placeholder dots should remain after finalize.\nFinal output:\n{final_text}"
);
}
/// Tests progressive rendering with no worktrees (fast path).
#[rstest]
fn test_list_progressive_fast_command(repo: TestRepo) {
let output = capture_progressive_output(
&repo,
"list",
&[],
ProgressiveCaptureOptions::with_byte_interval(600),
);
assert_eq!(output.exit_code, 0);
// Even fast commands should capture at least the final state
assert!(
!output.stages.is_empty(),
"Should capture at least one snapshot"
);
assert!(
output.final_output().contains("Branch"),
"Should have table header"
);
}