@mdxui/terminal 2.0.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.
- package/README.md +571 -0
- package/dist/ansi-css-Sk5mWtdK.d.ts +119 -0
- package/dist/ansi-css-V6JIHGsM.d.ts +119 -0
- package/dist/ansi-css-_3eSEU9d.d.ts +119 -0
- package/dist/chunk-3EFDH7PK.js +5235 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-3X5IR6WE.js +884 -0
- package/dist/chunk-4FV5ZDCE.js +5236 -0
- package/dist/chunk-4OVMSF2J.js +243 -0
- package/dist/chunk-63FEETIS.js +4048 -0
- package/dist/chunk-B43KP7XJ.js +884 -0
- package/dist/chunk-BMTJXWUV.js +655 -0
- package/dist/chunk-C3SVH4N7.js +882 -0
- package/dist/chunk-EVWR7Y47.js +874 -0
- package/dist/chunk-F6A5VWUC.js +1285 -0
- package/dist/chunk-FD7KW7GE.js +882 -0
- package/dist/chunk-GBQ6UD6I.js +655 -0
- package/dist/chunk-GMDD3M6U.js +5227 -0
- package/dist/chunk-JBHRXOXM.js +1058 -0
- package/dist/chunk-JFOO3EYO.js +1182 -0
- package/dist/chunk-JQ5H3WXL.js +1291 -0
- package/dist/chunk-JQD5NASE.js +234 -0
- package/dist/chunk-KRHJP5R7.js +592 -0
- package/dist/chunk-KWF6WVJE.js +962 -0
- package/dist/chunk-LHYQVN3H.js +1038 -0
- package/dist/chunk-M3TLQLGC.js +1032 -0
- package/dist/chunk-MVW4Q5OP.js +240 -0
- package/dist/chunk-NXCZSWLU.js +1294 -0
- package/dist/chunk-O25TNRO6.js +607 -0
- package/dist/chunk-PNECDA2I.js +884 -0
- package/dist/chunk-QIHWRLJR.js +962 -0
- package/dist/chunk-QW5YMQ7K.js +882 -0
- package/dist/chunk-R5U7XKVJ.js +16 -0
- package/dist/chunk-RP2MVQLR.js +962 -0
- package/dist/chunk-TP6RXGXA.js +1087 -0
- package/dist/chunk-TQQSTITZ.js +655 -0
- package/dist/chunk-X24GWXQV.js +1281 -0
- package/dist/components/index.d.ts +802 -0
- package/dist/components/index.js +149 -0
- package/dist/data/index.d.ts +2554 -0
- package/dist/data/index.js +51 -0
- package/dist/forms/index.d.ts +1596 -0
- package/dist/forms/index.js +464 -0
- package/dist/index-CQRFZntR.d.ts +867 -0
- package/dist/index.d.ts +579 -0
- package/dist/index.js +786 -0
- package/dist/interactive-D0JkWosD.d.ts +217 -0
- package/dist/keyboard/index.d.ts +2 -0
- package/dist/keyboard/index.js +43 -0
- package/dist/renderers/index.d.ts +546 -0
- package/dist/renderers/index.js +2157 -0
- package/dist/storybook/index.d.ts +396 -0
- package/dist/storybook/index.js +641 -0
- package/dist/theme/index.d.ts +1339 -0
- package/dist/theme/index.js +123 -0
- package/dist/types-Bxu5PAgA.d.ts +710 -0
- package/dist/types-CIlop5Ji.d.ts +701 -0
- package/dist/types-Ca8p_p5X.d.ts +710 -0
- package/package.json +90 -0
- package/src/__tests__/components/data/card.test.ts +458 -0
- package/src/__tests__/components/data/list.test.ts +473 -0
- package/src/__tests__/components/data/metrics.test.ts +541 -0
- package/src/__tests__/components/data/table.test.ts +448 -0
- package/src/__tests__/components/input/field.test.ts +555 -0
- package/src/__tests__/components/input/form.test.ts +870 -0
- package/src/__tests__/components/input/search.test.ts +1238 -0
- package/src/__tests__/components/input/select.test.ts +658 -0
- package/src/__tests__/components/navigation/breadcrumb.test.ts +923 -0
- package/src/__tests__/components/navigation/command-palette.test.ts +1095 -0
- package/src/__tests__/components/navigation/sidebar.test.ts +1018 -0
- package/src/__tests__/components/navigation/tabs.test.ts +995 -0
- package/src/__tests__/components.test.tsx +1197 -0
- package/src/__tests__/core/compiler.test.ts +986 -0
- package/src/__tests__/core/parser.test.ts +785 -0
- package/src/__tests__/core/tier-switcher.test.ts +1103 -0
- package/src/__tests__/core/types.test.ts +1398 -0
- package/src/__tests__/data/collections.test.ts +1337 -0
- package/src/__tests__/data/db.test.ts +1265 -0
- package/src/__tests__/data/reactive.test.ts +1010 -0
- package/src/__tests__/data/sync.test.ts +1614 -0
- package/src/__tests__/errors.test.ts +660 -0
- package/src/__tests__/forms/integration.test.ts +444 -0
- package/src/__tests__/integration.test.ts +905 -0
- package/src/__tests__/keyboard.test.ts +1791 -0
- package/src/__tests__/renderer.test.ts +489 -0
- package/src/__tests__/renderers/ansi-css.test.ts +948 -0
- package/src/__tests__/renderers/ansi.test.ts +1366 -0
- package/src/__tests__/renderers/ascii.test.ts +1360 -0
- package/src/__tests__/renderers/interactive.test.ts +2353 -0
- package/src/__tests__/renderers/markdown.test.ts +1483 -0
- package/src/__tests__/renderers/text.test.ts +1369 -0
- package/src/__tests__/renderers/unicode.test.ts +1307 -0
- package/src/__tests__/theme.test.ts +639 -0
- package/src/__tests__/utils/assertions.ts +685 -0
- package/src/__tests__/utils/index.ts +115 -0
- package/src/__tests__/utils/test-renderer.ts +381 -0
- package/src/__tests__/utils/utils.test.ts +560 -0
- package/src/components/containers/card.ts +56 -0
- package/src/components/containers/dialog.ts +53 -0
- package/src/components/containers/index.ts +9 -0
- package/src/components/containers/panel.ts +59 -0
- package/src/components/feedback/badge.ts +40 -0
- package/src/components/feedback/index.ts +8 -0
- package/src/components/feedback/spinner.ts +23 -0
- package/src/components/helpers.ts +81 -0
- package/src/components/index.ts +153 -0
- package/src/components/layout/breadcrumb.ts +31 -0
- package/src/components/layout/index.ts +10 -0
- package/src/components/layout/list.ts +29 -0
- package/src/components/layout/sidebar.ts +79 -0
- package/src/components/layout/table.ts +62 -0
- package/src/components/primitives/box.ts +95 -0
- package/src/components/primitives/button.ts +54 -0
- package/src/components/primitives/index.ts +11 -0
- package/src/components/primitives/input.ts +88 -0
- package/src/components/primitives/select.ts +97 -0
- package/src/components/primitives/text.ts +60 -0
- package/src/components/render.ts +155 -0
- package/src/components/templates/app.ts +43 -0
- package/src/components/templates/index.ts +8 -0
- package/src/components/templates/site.ts +54 -0
- package/src/components/types.ts +777 -0
- package/src/core/compiler.ts +718 -0
- package/src/core/parser.ts +127 -0
- package/src/core/tier-switcher.ts +607 -0
- package/src/core/types.ts +672 -0
- package/src/data/collection.ts +316 -0
- package/src/data/collections.ts +50 -0
- package/src/data/context.tsx +174 -0
- package/src/data/db.ts +127 -0
- package/src/data/hooks.ts +532 -0
- package/src/data/index.ts +138 -0
- package/src/data/reactive.ts +1225 -0
- package/src/data/saas-collections.ts +375 -0
- package/src/data/sync.ts +1213 -0
- package/src/data/types.ts +660 -0
- package/src/forms/converters.ts +512 -0
- package/src/forms/index.ts +133 -0
- package/src/forms/schemas.ts +403 -0
- package/src/forms/types.ts +476 -0
- package/src/index.ts +542 -0
- package/src/keyboard/focus.ts +748 -0
- package/src/keyboard/index.ts +96 -0
- package/src/keyboard/integration.ts +371 -0
- package/src/keyboard/manager.ts +377 -0
- package/src/keyboard/presets.ts +90 -0
- package/src/renderers/ansi-css.ts +576 -0
- package/src/renderers/ansi.ts +802 -0
- package/src/renderers/ascii.ts +680 -0
- package/src/renderers/breadcrumb.ts +480 -0
- package/src/renderers/command-palette.ts +802 -0
- package/src/renderers/components/field.ts +210 -0
- package/src/renderers/components/form.ts +327 -0
- package/src/renderers/components/index.ts +21 -0
- package/src/renderers/components/search.ts +449 -0
- package/src/renderers/components/select.ts +222 -0
- package/src/renderers/index.ts +101 -0
- package/src/renderers/interactive/component-handlers.ts +622 -0
- package/src/renderers/interactive/cursor-manager.ts +147 -0
- package/src/renderers/interactive/focus-manager.ts +279 -0
- package/src/renderers/interactive/index.ts +661 -0
- package/src/renderers/interactive/input-handler.ts +164 -0
- package/src/renderers/interactive/keyboard-handler.ts +212 -0
- package/src/renderers/interactive/mouse-handler.ts +167 -0
- package/src/renderers/interactive/state-manager.ts +109 -0
- package/src/renderers/interactive/types.ts +338 -0
- package/src/renderers/interactive-string.ts +299 -0
- package/src/renderers/interactive.ts +59 -0
- package/src/renderers/markdown.ts +950 -0
- package/src/renderers/sidebar.ts +549 -0
- package/src/renderers/tabs.ts +682 -0
- package/src/renderers/text.ts +791 -0
- package/src/renderers/unicode.ts +917 -0
- package/src/renderers/utils.ts +942 -0
- package/src/router/adapters.ts +383 -0
- package/src/router/types.ts +140 -0
- package/src/router/utils.ts +452 -0
- package/src/schemas.ts +205 -0
- package/src/storybook/index.ts +91 -0
- package/src/storybook/interactive-decorator.tsx +659 -0
- package/src/storybook/keyboard-simulator.ts +501 -0
- package/src/theme/ansi-codes.ts +80 -0
- package/src/theme/box-drawing.ts +132 -0
- package/src/theme/color-convert.ts +254 -0
- package/src/theme/color-support.ts +321 -0
- package/src/theme/index.ts +134 -0
- package/src/theme/strip-ansi.ts +50 -0
- package/src/theme/tailwind-map.ts +469 -0
- package/src/theme/text-styles.ts +206 -0
- package/src/theme/theme-system.ts +568 -0
- package/src/types.ts +103 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mdxui/terminal Test Utilities
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive test utilities for testing terminal components.
|
|
5
|
+
* This module provides:
|
|
6
|
+
*
|
|
7
|
+
* - **Mock Renderer**: Test components without a real terminal
|
|
8
|
+
* - **Assertions**: Terminal-aware assertion helpers
|
|
9
|
+
* - **Snapshot Utilities**: Prepare output for snapshot testing
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import {
|
|
14
|
+
* createTestRenderer,
|
|
15
|
+
* renderToLines,
|
|
16
|
+
* expectTerminalContains,
|
|
17
|
+
* expectBoxDrawing,
|
|
18
|
+
* expectStyle,
|
|
19
|
+
* toSnapshot,
|
|
20
|
+
* } from '../utils'
|
|
21
|
+
*
|
|
22
|
+
* describe('MyComponent', () => {
|
|
23
|
+
* it('renders correctly', () => {
|
|
24
|
+
* const output = renderToLines(<Box border="single"><Text>Hello</Text></Box>)
|
|
25
|
+
*
|
|
26
|
+
* expectTerminalContains(output, 'Hello')
|
|
27
|
+
* expectBoxDrawing(output, 'single')
|
|
28
|
+
* expect(toSnapshot(output)).toMatchSnapshot()
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* it('applies styling', () => {
|
|
32
|
+
* const output = renderToLines(<Text bold color="red">Error</Text>)
|
|
33
|
+
*
|
|
34
|
+
* expectStyle(output, 'bold')
|
|
35
|
+
* expectForegroundColor(output, 'red')
|
|
36
|
+
* })
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @packageDocumentation
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Mock Renderer
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
// Core renderer
|
|
49
|
+
createTestRenderer,
|
|
50
|
+
createTestRoot,
|
|
51
|
+
// Convenience functions
|
|
52
|
+
renderToLines,
|
|
53
|
+
renderToString,
|
|
54
|
+
prepareSnapshot,
|
|
55
|
+
// Mock factory functions (for vi.mock)
|
|
56
|
+
mockCreateCliRenderer,
|
|
57
|
+
mockCreateRoot,
|
|
58
|
+
// Types
|
|
59
|
+
type TestRenderer,
|
|
60
|
+
type TestRendererConfig,
|
|
61
|
+
type TestRoot,
|
|
62
|
+
type SnapshotOptions,
|
|
63
|
+
type RenderContext,
|
|
64
|
+
} from './test-renderer'
|
|
65
|
+
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Assertions
|
|
68
|
+
// ============================================================================
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
// ANSI utilities
|
|
72
|
+
stripAnsi,
|
|
73
|
+
hasAnsiCodes,
|
|
74
|
+
visibleLength,
|
|
75
|
+
extractAnsiCodes,
|
|
76
|
+
getPlainContent,
|
|
77
|
+
// Content assertions
|
|
78
|
+
expectTerminalContains,
|
|
79
|
+
expectTerminalNotContains,
|
|
80
|
+
expectTerminalMatches,
|
|
81
|
+
expectLineContains,
|
|
82
|
+
expectLineCount,
|
|
83
|
+
expectMinLines,
|
|
84
|
+
// ANSI style assertions
|
|
85
|
+
expectAnsiCode,
|
|
86
|
+
expectNoAnsiCode,
|
|
87
|
+
expectStyle,
|
|
88
|
+
expectForegroundColor,
|
|
89
|
+
expectBackgroundColor,
|
|
90
|
+
expectReset,
|
|
91
|
+
expectAnsi256Color,
|
|
92
|
+
expectTrueColor,
|
|
93
|
+
// Box drawing assertions
|
|
94
|
+
expectBoxDrawing,
|
|
95
|
+
expectHorizontalLine,
|
|
96
|
+
expectVerticalLine,
|
|
97
|
+
expectNoBoxDrawing,
|
|
98
|
+
// Dimension assertions
|
|
99
|
+
expectMaxWidth,
|
|
100
|
+
expectExactWidth,
|
|
101
|
+
expectFitsDimensions,
|
|
102
|
+
// Snapshot utilities
|
|
103
|
+
toSnapshot,
|
|
104
|
+
terminalOutputEquals,
|
|
105
|
+
expectTerminalEquals,
|
|
106
|
+
// Component-specific assertions
|
|
107
|
+
expectCursor,
|
|
108
|
+
expectFocused,
|
|
109
|
+
expectDisabled,
|
|
110
|
+
expectSelected,
|
|
111
|
+
// Types
|
|
112
|
+
type AnsiStyleName,
|
|
113
|
+
type AnsiColorName,
|
|
114
|
+
type AnsiBgColorName,
|
|
115
|
+
} from './assertions'
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mdxui/terminal Test Renderer
|
|
3
|
+
*
|
|
4
|
+
* Mock terminal renderer for testing terminal components without requiring
|
|
5
|
+
* a real terminal or @opentui/core. Provides predictable output for assertions.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { createTestRenderer, renderToLines } from './test-renderer'
|
|
10
|
+
* import { Box, Text } from '@mdxui/terminal'
|
|
11
|
+
*
|
|
12
|
+
* // Quick rendering
|
|
13
|
+
* const lines = await renderToLines(
|
|
14
|
+
* <Box border="single"><Text>Hello</Text></Box>
|
|
15
|
+
* )
|
|
16
|
+
* expect(lines).toContain('Hello')
|
|
17
|
+
*
|
|
18
|
+
* // Full control
|
|
19
|
+
* const renderer = createTestRenderer({ width: 40, height: 10 })
|
|
20
|
+
* const output = renderer.render(<App />)
|
|
21
|
+
* expect(renderer.getBuffer()).toMatchSnapshot()
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type { ReactElement, ReactNode } from 'react'
|
|
26
|
+
import type { RenderContext } from '../../components/types'
|
|
27
|
+
import { renderElement } from '../../components/render'
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Types
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Configuration options for the test renderer
|
|
35
|
+
*/
|
|
36
|
+
export interface TestRendererConfig {
|
|
37
|
+
/** Terminal width in columns (default: 80) */
|
|
38
|
+
width?: number
|
|
39
|
+
/** Terminal height in rows (default: 24) */
|
|
40
|
+
height?: number
|
|
41
|
+
/** Enable color output (default: true) */
|
|
42
|
+
colors?: boolean
|
|
43
|
+
/** Color support level (default: 'truecolor') */
|
|
44
|
+
colorSupport?: 'none' | '16' | '256' | 'truecolor'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Mock renderer instance for testing
|
|
49
|
+
*/
|
|
50
|
+
export interface TestRenderer {
|
|
51
|
+
/** Terminal width in columns */
|
|
52
|
+
readonly width: number
|
|
53
|
+
/** Terminal height in rows */
|
|
54
|
+
readonly height: number
|
|
55
|
+
/** Render a React element and return output lines */
|
|
56
|
+
render(element: ReactElement): string[]
|
|
57
|
+
/** Get the current buffer as a 2D array (rows x columns) */
|
|
58
|
+
getBuffer(): string[][]
|
|
59
|
+
/** Get the current output as a single string with newlines */
|
|
60
|
+
toString(): string
|
|
61
|
+
/** Clear the buffer */
|
|
62
|
+
clear(): void
|
|
63
|
+
/** Get the last rendered output */
|
|
64
|
+
getLastOutput(): string[]
|
|
65
|
+
/** Configure the renderer */
|
|
66
|
+
configure(config: Partial<TestRendererConfig>): void
|
|
67
|
+
/** Mock lifecycle methods (for compatibility with CliRenderer interface) */
|
|
68
|
+
start(): void
|
|
69
|
+
stop(): void
|
|
70
|
+
destroy(): void
|
|
71
|
+
requestRender(): void
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Mock root instance for React rendering
|
|
76
|
+
*/
|
|
77
|
+
export interface TestRoot {
|
|
78
|
+
/** Render a React element */
|
|
79
|
+
render(element: ReactNode): void
|
|
80
|
+
/** Unmount and clean up */
|
|
81
|
+
unmount(): void
|
|
82
|
+
/** Get the rendered output */
|
|
83
|
+
getOutput(): string[]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Snapshot options for terminal output
|
|
88
|
+
*/
|
|
89
|
+
export interface SnapshotOptions {
|
|
90
|
+
/** Strip ANSI codes before comparison (default: false) */
|
|
91
|
+
stripAnsi?: boolean
|
|
92
|
+
/** Trim trailing whitespace from lines (default: true) */
|
|
93
|
+
trimTrailingWhitespace?: boolean
|
|
94
|
+
/** Normalize line endings (default: true) */
|
|
95
|
+
normalizeLineEndings?: boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Mock Renderer Implementation
|
|
100
|
+
// ============================================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create a mock terminal renderer for testing.
|
|
104
|
+
*
|
|
105
|
+
* This renderer simulates the @opentui/core renderer behavior
|
|
106
|
+
* but renders to an in-memory buffer instead of the terminal.
|
|
107
|
+
*
|
|
108
|
+
* @param config - Optional configuration
|
|
109
|
+
* @returns A mock renderer instance
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* const renderer = createTestRenderer({ width: 40, height: 10 })
|
|
114
|
+
* const lines = renderer.render(<Box>Test</Box>)
|
|
115
|
+
* expect(lines[0]).toContain('Test')
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export function createTestRenderer(config: TestRendererConfig = {}): TestRenderer {
|
|
119
|
+
let width = config.width ?? 80
|
|
120
|
+
let height = config.height ?? 24
|
|
121
|
+
let colors = config.colors ?? true
|
|
122
|
+
let colorSupport = config.colorSupport ?? 'truecolor'
|
|
123
|
+
|
|
124
|
+
// Internal buffer as 2D array
|
|
125
|
+
let buffer: string[][] = []
|
|
126
|
+
let lastOutput: string[] = []
|
|
127
|
+
|
|
128
|
+
// Initialize empty buffer
|
|
129
|
+
const initBuffer = () => {
|
|
130
|
+
buffer = Array.from({ length: height }, () =>
|
|
131
|
+
Array.from({ length: width }, () => ' ')
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
initBuffer()
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
get width() {
|
|
139
|
+
return width
|
|
140
|
+
},
|
|
141
|
+
get height() {
|
|
142
|
+
return height
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
render(element: ReactElement): string[] {
|
|
146
|
+
const context: RenderContext = {
|
|
147
|
+
width,
|
|
148
|
+
colors,
|
|
149
|
+
colorSupport,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const lines = renderElement(element, context)
|
|
153
|
+
lastOutput = lines
|
|
154
|
+
|
|
155
|
+
// Update buffer with rendered content
|
|
156
|
+
initBuffer()
|
|
157
|
+
lines.forEach((line, row) => {
|
|
158
|
+
if (row < height) {
|
|
159
|
+
const chars = [...line]
|
|
160
|
+
chars.forEach((char, col) => {
|
|
161
|
+
if (col < width) {
|
|
162
|
+
buffer[row][col] = char
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return lines
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
getBuffer(): string[][] {
|
|
172
|
+
return buffer.map(row => [...row])
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
toString(): string {
|
|
176
|
+
return lastOutput.join('\n')
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
clear(): void {
|
|
180
|
+
initBuffer()
|
|
181
|
+
lastOutput = []
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
getLastOutput(): string[] {
|
|
185
|
+
return [...lastOutput]
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
configure(newConfig: Partial<TestRendererConfig>): void {
|
|
189
|
+
if (newConfig.width !== undefined) width = newConfig.width
|
|
190
|
+
if (newConfig.height !== undefined) height = newConfig.height
|
|
191
|
+
if (newConfig.colors !== undefined) colors = newConfig.colors
|
|
192
|
+
if (newConfig.colorSupport !== undefined) colorSupport = newConfig.colorSupport
|
|
193
|
+
initBuffer()
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// Mock lifecycle methods (no-op for testing)
|
|
197
|
+
start(): void {},
|
|
198
|
+
stop(): void {},
|
|
199
|
+
destroy(): void {},
|
|
200
|
+
requestRender(): void {},
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create a mock root for testing React trees.
|
|
206
|
+
*
|
|
207
|
+
* @param renderer - The test renderer to use
|
|
208
|
+
* @returns A mock root instance
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```tsx
|
|
212
|
+
* const renderer = createTestRenderer()
|
|
213
|
+
* const root = createTestRoot(renderer)
|
|
214
|
+
* root.render(<App />)
|
|
215
|
+
* expect(root.getOutput()).toContain('Welcome')
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function createTestRoot(renderer: TestRenderer): TestRoot {
|
|
219
|
+
let currentOutput: string[] = []
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
render(element: ReactNode): void {
|
|
223
|
+
if (element === null || element === undefined) {
|
|
224
|
+
currentOutput = []
|
|
225
|
+
renderer.clear()
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
currentOutput = renderer.render(element as ReactElement)
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
unmount(): void {
|
|
233
|
+
currentOutput = []
|
|
234
|
+
renderer.clear()
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
getOutput(): string[] {
|
|
238
|
+
return [...currentOutput]
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ============================================================================
|
|
244
|
+
// Helper Functions
|
|
245
|
+
// ============================================================================
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Render a React element directly to lines without creating a renderer.
|
|
249
|
+
*
|
|
250
|
+
* This is a convenience function for quick tests that don't need
|
|
251
|
+
* full renderer control.
|
|
252
|
+
*
|
|
253
|
+
* @param element - The React element to render
|
|
254
|
+
* @param options - Optional configuration
|
|
255
|
+
* @returns Array of rendered output lines
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```tsx
|
|
259
|
+
* const lines = await renderToLines(<Text color="red">Error</Text>)
|
|
260
|
+
* expect(lines[0]).toContain('Error')
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export function renderToLines(
|
|
264
|
+
element: ReactElement,
|
|
265
|
+
options: TestRendererConfig = {}
|
|
266
|
+
): string[] {
|
|
267
|
+
const renderer = createTestRenderer(options)
|
|
268
|
+
return renderer.render(element)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Render a React element to a single string with newlines.
|
|
273
|
+
*
|
|
274
|
+
* @param element - The React element to render
|
|
275
|
+
* @param options - Optional configuration
|
|
276
|
+
* @returns The rendered output as a string
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```tsx
|
|
280
|
+
* const output = renderToString(<Box>Hello</Box>)
|
|
281
|
+
* expect(output).toMatchSnapshot()
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
export function renderToString(
|
|
285
|
+
element: ReactElement,
|
|
286
|
+
options: TestRendererConfig = {}
|
|
287
|
+
): string {
|
|
288
|
+
const lines = renderToLines(element, options)
|
|
289
|
+
return lines.join('\n')
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Prepare terminal output for snapshot comparison.
|
|
294
|
+
*
|
|
295
|
+
* Normalizes the output to ensure consistent snapshot matching
|
|
296
|
+
* across different environments.
|
|
297
|
+
*
|
|
298
|
+
* @param output - The raw output (string or array of lines)
|
|
299
|
+
* @param options - Normalization options
|
|
300
|
+
* @returns Normalized output string
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```tsx
|
|
304
|
+
* const output = renderer.render(<Component />)
|
|
305
|
+
* expect(prepareSnapshot(output)).toMatchSnapshot()
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
export function prepareSnapshot(
|
|
309
|
+
output: string | string[],
|
|
310
|
+
options: SnapshotOptions = {}
|
|
311
|
+
): string {
|
|
312
|
+
const {
|
|
313
|
+
stripAnsi = false,
|
|
314
|
+
trimTrailingWhitespace = true,
|
|
315
|
+
normalizeLineEndings = true,
|
|
316
|
+
} = options
|
|
317
|
+
|
|
318
|
+
let text = Array.isArray(output) ? output.join('\n') : output
|
|
319
|
+
|
|
320
|
+
// Strip ANSI codes if requested
|
|
321
|
+
if (stripAnsi) {
|
|
322
|
+
text = text.replace(/\x1b\[[\d;]*m/g, '')
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Normalize line endings
|
|
326
|
+
if (normalizeLineEndings) {
|
|
327
|
+
text = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Trim trailing whitespace from each line
|
|
331
|
+
if (trimTrailingWhitespace) {
|
|
332
|
+
text = text
|
|
333
|
+
.split('\n')
|
|
334
|
+
.map(line => line.trimEnd())
|
|
335
|
+
.join('\n')
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return text
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Create a mock @opentui/core createCliRenderer for testing.
|
|
343
|
+
*
|
|
344
|
+
* This returns a mock that can be used with vi.mock() or jest.mock()
|
|
345
|
+
* to replace the real OpenTUI renderer in tests.
|
|
346
|
+
*
|
|
347
|
+
* @param config - Optional configuration
|
|
348
|
+
* @returns A mock createCliRenderer function
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```tsx
|
|
352
|
+
* vi.mock('@opentui/core', () => ({
|
|
353
|
+
* createCliRenderer: mockCreateCliRenderer({ width: 40 }),
|
|
354
|
+
* }))
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
export function mockCreateCliRenderer(config: TestRendererConfig = {}) {
|
|
358
|
+
return async () => createTestRenderer(config)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Create a mock @opentui/react createRoot for testing.
|
|
363
|
+
*
|
|
364
|
+
* @returns A mock createRoot function
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```tsx
|
|
368
|
+
* vi.mock('@opentui/react', () => ({
|
|
369
|
+
* createRoot: mockCreateRoot(),
|
|
370
|
+
* }))
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
export function mockCreateRoot() {
|
|
374
|
+
return (renderer: TestRenderer) => createTestRoot(renderer)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ============================================================================
|
|
378
|
+
// Exports
|
|
379
|
+
// ============================================================================
|
|
380
|
+
|
|
381
|
+
export { type RenderContext }
|