| |
| |
| |
| |
| |
|
|
| import { describe, it, expect } from 'vitest'; |
| import { render } from '../../../test-utils/render.js'; |
| import { ExpandableText, MAX_WIDTH } from './ExpandableText.js'; |
|
|
| describe('ExpandableText', () => { |
| const color = 'white'; |
| const flat = (s: string | undefined) => (s ?? '').replace(/\n/g, ''); |
|
|
| it('renders plain label when no match (short label)', async () => { |
| const renderResult = await render( |
| <ExpandableText |
| label="simple command" |
| userInput="" |
| matchedIndex={undefined} |
| textColor={color} |
| isExpanded={false} |
| />, |
| ); |
| const { unmount } = renderResult; |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('truncates long label when collapsed and no match', async () => { |
| const long = 'x'.repeat(MAX_WIDTH + 25); |
| const renderResult = await render( |
| <ExpandableText |
| label={long} |
| userInput="" |
| textColor={color} |
| isExpanded={false} |
| />, |
| ); |
| const { lastFrame, unmount } = renderResult; |
| const out = lastFrame(); |
| const f = flat(out); |
| expect(f.endsWith('...')).toBe(true); |
| expect(f.length).toBe(MAX_WIDTH + 3); |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('shows full long label when expanded and no match', async () => { |
| const long = 'y'.repeat(MAX_WIDTH + 25); |
| const renderResult = await render( |
| <ExpandableText |
| label={long} |
| userInput="" |
| textColor={color} |
| isExpanded={true} |
| />, |
| ); |
| const { lastFrame, unmount } = renderResult; |
| const out = lastFrame(); |
| const f = flat(out); |
| expect(f.length).toBe(long.length); |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('highlights matched substring when expanded (text only visible)', async () => { |
| const label = 'run: git commit -m "feat: add search"'; |
| const userInput = 'commit'; |
| const matchedIndex = label.indexOf(userInput); |
| const renderResult = await render( |
| <ExpandableText |
| label={label} |
| userInput={userInput} |
| matchedIndex={matchedIndex} |
| textColor={color} |
| isExpanded={true} |
| />, |
| 100, |
| ); |
| const { unmount } = renderResult; |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('creates centered window around match when collapsed', async () => { |
| const prefix = 'cd_/very/long/path/that/keeps/going/'.repeat(3); |
| const core = 'search-here'; |
| const suffix = '/and/then/some/more/components/'.repeat(3); |
| const label = prefix + core + suffix; |
| const matchedIndex = prefix.length; |
| const renderResult = await render( |
| <ExpandableText |
| label={label} |
| userInput={core} |
| matchedIndex={matchedIndex} |
| textColor={color} |
| isExpanded={false} |
| />, |
| 100, |
| ); |
| const { lastFrame, unmount } = renderResult; |
| const out = lastFrame(); |
| const f = flat(out); |
| expect(f.includes(core)).toBe(true); |
| expect(f.startsWith('...')).toBe(true); |
| expect(f.endsWith('...')).toBe(true); |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('truncates match itself when match is very long', async () => { |
| const prefix = 'find '; |
| const core = 'x'.repeat(MAX_WIDTH + 25); |
| const suffix = ' in this text'; |
| const label = prefix + core + suffix; |
| const matchedIndex = prefix.length; |
| const renderResult = await render( |
| <ExpandableText |
| label={label} |
| userInput={core} |
| matchedIndex={matchedIndex} |
| textColor={color} |
| isExpanded={false} |
| />, |
| ); |
| const { lastFrame, unmount } = renderResult; |
| const out = lastFrame(); |
| const f = flat(out); |
| expect(f.includes('...')).toBe(true); |
| expect(f.startsWith('...')).toBe(false); |
| expect(f.endsWith('...')).toBe(true); |
| expect(f.length).toBe(MAX_WIDTH + 2); |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
|
|
| it('respects custom maxWidth', async () => { |
| const customWidth = 50; |
| const long = 'z'.repeat(100); |
| const renderResult = await render( |
| <ExpandableText |
| label={long} |
| userInput="" |
| textColor={color} |
| isExpanded={false} |
| maxWidth={customWidth} |
| />, |
| ); |
| const { lastFrame, unmount } = renderResult; |
| const out = lastFrame(); |
| const f = flat(out); |
| expect(f.endsWith('...')).toBe(true); |
| expect(f.length).toBe(customWidth + 3); |
| await expect(renderResult).toMatchSvgSnapshot(); |
| unmount(); |
| }); |
| }); |
|
|