Skip to content

Commit 734e64e

Browse files
committed
test: add limit options tests
1 parent 0036ee4 commit 734e64e

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed

packages/prompts/test/limit-options.test.ts

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import color from 'picocolors';
12
import { beforeEach, describe, expect, test } from 'vitest';
23
import { type LimitOptionsParams, limitOptions } from '../src/index.js';
34
import { MockWritable } from './test-utils.js';
@@ -25,4 +26,219 @@ describe('limitOptions', () => {
2526
const result = limitOptions(options);
2627
expect(result).toEqual(['Item 1', 'Item 2', 'Item 3']);
2728
});
29+
30+
test('clamps to 5 rows minimum', async () => {
31+
options.options = [
32+
{ value: 'Item 1' },
33+
{ value: 'Item 2' },
34+
{ value: 'Item 3' },
35+
{ value: 'Item 4' },
36+
{ value: 'Item 5' },
37+
{ value: 'Item 6' },
38+
{ value: 'Item 7' },
39+
];
40+
options.maxItems = 3;
41+
const result = limitOptions(options);
42+
expect(result).toEqual(['Item 1', 'Item 2', 'Item 3', 'Item 4', color.dim('...')]);
43+
});
44+
45+
test('returns sliding window when cursor moves down', async () => {
46+
options.options = [
47+
{ value: 'Item 1' },
48+
{ value: 'Item 2' },
49+
{ value: 'Item 3' },
50+
{ value: 'Item 4' },
51+
{ value: 'Item 5' },
52+
{ value: 'Item 6' },
53+
{ value: 'Item 7' },
54+
{ value: 'Item 8' },
55+
{ value: 'Item 9' },
56+
{ value: 'Item 10' },
57+
];
58+
output.rows = 20;
59+
options.maxItems = 5;
60+
options.cursor = 6;
61+
const result = limitOptions(options);
62+
expect(result).toEqual([color.dim('...'), 'Item 6', 'Item 7', 'Item 8', color.dim('...')]);
63+
});
64+
65+
test('returns sliding window near end of list', async () => {
66+
options.options = [
67+
{ value: 'Item 1' },
68+
{ value: 'Item 2' },
69+
{ value: 'Item 3' },
70+
{ value: 'Item 4' },
71+
{ value: 'Item 5' },
72+
{ value: 'Item 6' },
73+
{ value: 'Item 7' },
74+
{ value: 'Item 8' },
75+
{ value: 'Item 9' },
76+
{ value: 'Item 10' },
77+
];
78+
options.maxItems = 5;
79+
options.cursor = 8;
80+
const result = limitOptions(options);
81+
expect(result).toEqual([color.dim('...'), 'Item 7', 'Item 8', 'Item 9', 'Item 10']);
82+
});
83+
84+
test('handles empty options list', async () => {
85+
options.options = [];
86+
const result = limitOptions(options);
87+
expect(result).toEqual([]);
88+
});
89+
90+
test('if items exceed output height, clamp to fit', async () => {
91+
options.options = [
92+
{ value: 'Item 1' },
93+
{ value: 'Item 2' },
94+
{ value: 'Item 3' },
95+
{ value: 'Item 4' },
96+
{ value: 'Item 5' },
97+
{ value: 'Item 6' },
98+
{ value: 'Item 7' },
99+
{ value: 'Item 8' },
100+
{ value: 'Item 9' },
101+
{ value: 'Item 10' },
102+
];
103+
output.rows = 7;
104+
options.maxItems = 10;
105+
const result = limitOptions(options);
106+
expect(result).toEqual(['Item 1', 'Item 2', 'Item 3', color.dim('...')]);
107+
});
108+
109+
test('handle multi-line item clamping (start)', async () => {
110+
options.options = [
111+
{ value: 'Item 1' },
112+
{ value: 'Item 2' },
113+
{
114+
value: Array.from({ length: 4 })
115+
.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)
116+
.join('\n'),
117+
},
118+
{ value: 'Item 4' },
119+
{ value: 'Item 5' },
120+
{ value: 'Item 6' },
121+
{ value: 'Item 7' },
122+
{ value: 'Item 8' },
123+
{ value: 'Item 9' },
124+
{ value: 'Item 10' },
125+
];
126+
output.rows = 14;
127+
options.maxItems = 10;
128+
const result = limitOptions(options);
129+
expect(result).toEqual([
130+
'Item 1',
131+
'Item 2',
132+
'A long item that will take up a lot of space (line 0)',
133+
'A long item that will take up a lot of space (line 1)',
134+
'A long item that will take up a lot of space (line 2)',
135+
'A long item that will take up a lot of space (line 3)',
136+
'Item 4',
137+
'Item 5',
138+
'Item 6',
139+
'Item 7',
140+
'Item 8',
141+
color.dim('...'),
142+
]);
143+
});
144+
145+
test('handle multi-line item clamping (middle)', async () => {
146+
options.options = [
147+
{ value: 'Item 1' },
148+
{ value: 'Item 2' },
149+
{ value: 'Item 3' },
150+
{ value: 'Item 4' },
151+
{
152+
value: Array.from({ length: 4 })
153+
.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)
154+
.join('\n'),
155+
},
156+
{ value: 'Item 6' },
157+
{ value: 'Item 7' },
158+
{ value: 'Item 8' },
159+
{ value: 'Item 9' },
160+
{ value: 'Item 10' },
161+
];
162+
output.rows = 14;
163+
options.maxItems = 10;
164+
options.cursor = 7;
165+
const result = limitOptions(options);
166+
expect(result).toEqual([
167+
color.dim('...'),
168+
'Item 2',
169+
'Item 3',
170+
'Item 4',
171+
'A long item that will take up a lot of space (line 0)',
172+
'A long item that will take up a lot of space (line 1)',
173+
'A long item that will take up a lot of space (line 2)',
174+
'A long item that will take up a lot of space (line 3)',
175+
'Item 6',
176+
'Item 7',
177+
'Item 8',
178+
color.dim('...'),
179+
]);
180+
});
181+
182+
test('handle multi-line item clamping (end)', async () => {
183+
options.options = [
184+
{ value: 'Item 1' },
185+
{ value: 'Item 2' },
186+
{ value: 'Item 3' },
187+
{ value: 'Item 4' },
188+
{ value: 'Item 5' },
189+
{ value: 'Item 6' },
190+
{ value: 'Item 7' },
191+
{
192+
value: Array.from({ length: 4 })
193+
.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)
194+
.join('\n'),
195+
},
196+
{ value: 'Item 9' },
197+
{ value: 'Item 10' },
198+
];
199+
output.rows = 14;
200+
options.maxItems = 10;
201+
options.cursor = 9;
202+
const result = limitOptions(options);
203+
expect(result).toEqual([
204+
color.dim('...'),
205+
'Item 4',
206+
'Item 5',
207+
'Item 6',
208+
'Item 7',
209+
'A long item that will take up a lot of space (line 0)',
210+
'A long item that will take up a lot of space (line 1)',
211+
'A long item that will take up a lot of space (line 2)',
212+
'A long item that will take up a lot of space (line 3)',
213+
'Item 9',
214+
'Item 10',
215+
]);
216+
});
217+
218+
test('style option is used to style lines', async () => {
219+
options.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3' }];
220+
options.maxItems = 5;
221+
options.style = (option) => `-- ${option.value} --`;
222+
const result = limitOptions(options);
223+
expect(result).toEqual(['-- Item 1 --', '-- Item 2 --', '-- Item 3 --']);
224+
});
225+
226+
test('style option styles across multi-line items', async () => {
227+
options.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3\nContinued' }];
228+
options.maxItems = 5;
229+
options.style = (option) => `-- ${option.value} --`;
230+
const result = limitOptions(options);
231+
expect(result).toEqual(['-- Item 1 --', '-- Item 2 --', '-- Item 3', 'Continued --']);
232+
});
233+
234+
test('style option receives correct cursor index', async () => {
235+
options.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3' }];
236+
options.maxItems = 5;
237+
options.cursor = 1;
238+
options.style = (option, isSelected) => {
239+
return isSelected ? `-- ${option.value} --` : option.value;
240+
};
241+
const result = limitOptions(options);
242+
expect(result).toEqual(['Item 1', '-- Item 2 --', 'Item 3']);
243+
});
28244
});

0 commit comments

Comments
 (0)