11import { assert , describe , test } from "@rezi-ui/testkit" ;
2- import type React from "react" ;
3- import { useEffect , useState } from "react" ;
4- import { Text , Transform , render } from "../index.js" ;
2+ import { Transform } from "ink" ;
3+ import Gradient from "ink-gradient" ;
4+ import Spinner from "ink-spinner" ;
5+ import React from "react" ;
6+ import { Box , type DOMElement , Text , getInnerHeight , getScrollHeight , render } from "../index.js" ;
57import {
68 StubBackend ,
79 encodeZrevBatchV1 ,
@@ -18,30 +20,31 @@ async function pushInitialResize(backend: StubBackend): Promise<void> {
1820 await flushMicrotasks ( 10 ) ;
1921}
2022
21- describe ( "third-party compatibility smoke" , ( ) => {
22- test ( "ink-spinner pattern (stateful interval + <Text>) triggers render updates" , async ( ) => {
23- function SpinnerLike ( ) {
24- const frames = [ "-" , "\\" , "|" , "/" ] as const ;
25- const [ frame , setFrame ] = useState ( 0 ) ;
23+ async function renderToLastFrameBytes ( tree : React . ReactNode ) : Promise < Uint8Array > {
24+ const backend = new StubBackend ( ) ;
25+ const inst = render ( tree , { internal_backend : backend , exitOnCtrlC : false } ) ;
2626
27- useEffect ( ( ) => {
28- const timer = setInterval ( ( ) => {
29- setFrame ( ( prev ) => ( prev + 1 ) % frames . length ) ;
30- } , 10 ) ;
31- return ( ) => clearInterval ( timer ) ;
32- } , [ frames . length ] ) ;
27+ await flushMicrotasks ( 10 ) ;
28+ await pushInitialResize ( backend ) ;
29+
30+ const bytes = backend . requestedFrames [ backend . requestedFrames . length - 1 ] ?? new Uint8Array ( ) ;
3331
34- return < Text > { frames [ frame ] } </ Text > ;
35- }
32+ inst . unmount ( ) ;
33+ await inst . waitUntilExit ( ) ;
3634
35+ return bytes ;
36+ }
37+
38+ describe ( "third-party compatibility (real packages)" , ( ) => {
39+ test ( "ink-spinner renders and advances frames over time" , async ( ) => {
3740 const backend = new StubBackend ( ) ;
38- const inst = render ( < SpinnerLike /> , { internal_backend : backend , exitOnCtrlC : false } ) ;
41+ const inst = render ( < Spinner type = "dots" /> , { internal_backend : backend , exitOnCtrlC : false } ) ;
3942
4043 await flushMicrotasks ( 10 ) ;
4144 await pushInitialResize ( backend ) ;
4245
4346 const initialFrames = backend . requestedFrames . length ;
44- await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 40 ) ) ;
47+ await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 140 ) ) ;
4548 await flushMicrotasks ( 10 ) ;
4649
4750 assert . ok ( backend . requestedFrames . length > initialFrames ) ;
@@ -50,30 +53,62 @@ describe("third-party compatibility smoke", () => {
5053 await inst . waitUntilExit ( ) ;
5154 } ) ;
5255
53- test ( "ink-gradient pattern (Transform transform callback) receives flattened text" , async ( ) => {
54- let lastInput = "" ;
55-
56- function GradientLike ( props : Readonly < { children : React . ReactNode } > ) {
57- const transform = ( children : string ) => {
58- lastInput = children ;
59- return `\u001B[31m${ children } \u001B[39m` ;
60- } ;
56+ test ( "ink-gradient uses Ink Transform behavior with real package runtime" , async ( ) => {
57+ const gradientElement = (
58+ Gradient as unknown as ( props : {
59+ name : string ;
60+ children : React . ReactNode ;
61+ } ) => React . ReactElement < {
62+ transform : ( input : string ) => string ;
63+ children : React . ReactNode ;
64+ } >
65+ ) ( {
66+ name : "rainbow" ,
67+ children : < Text > rainbow</ Text > ,
68+ } ) ;
69+
70+ assert . equal ( gradientElement . type , Transform ) ;
71+ assert . equal ( typeof gradientElement . props . transform , "function" ) ;
72+
73+ const frame = await renderToLastFrameBytes (
74+ < Gradient name = "rainbow" >
75+ < Text > rainbow</ Text >
76+ </ Gradient > ,
77+ ) ;
6178
62- return < Transform transform = { transform } > { props . children } </ Transform > ;
63- }
79+ assert . ok ( frame . length > 0 ) ;
80+ } ) ;
6481
82+ test ( "third-party components remain compatible with scroll measurement semantics" , async ( ) => {
6583 const backend = new StubBackend ( ) ;
84+ const containerRef = React . createRef < DOMElement > ( ) ;
85+
6686 const inst = render (
67- < GradientLike >
68- < Text > rainbow</ Text >
69- </ GradientLike > ,
87+ < Box
88+ ref = { containerRef }
89+ width = { 20 }
90+ height = { 1 }
91+ flexDirection = "column"
92+ overflowY = "scroll"
93+ overflowX = "hidden"
94+ scrollTop = { 1 }
95+ >
96+ < Spinner type = "line" />
97+ < Gradient name = "pastel" >
98+ < Text > line-2</ Text >
99+ </ Gradient >
100+ < Text > line-3</ Text >
101+ </ Box > ,
70102 { internal_backend : backend , exitOnCtrlC : false } ,
71103 ) ;
72104
73105 await flushMicrotasks ( 10 ) ;
74106 await pushInitialResize ( backend ) ;
75107
76- assert . equal ( lastInput , "rainbow" ) ;
108+ const container = containerRef . current ;
109+ assert . ok ( container ) ;
110+ assert . equal ( getInnerHeight ( container ) , 1 ) ;
111+ assert . ok ( getScrollHeight ( container ) >= 3 ) ;
77112 assert . ok ( backend . requestedFrames . length >= 1 ) ;
78113
79114 inst . unmount ( ) ;
0 commit comments