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 Gradient from "ink-gradient" ;
3+ import { Transform } from "ink" ;
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,60 @@ 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 = ( Gradient as unknown as ( props : {
58+ name : string ;
59+ children : React . ReactNode ;
60+ } ) => React . ReactElement < {
61+ transform : ( input : string ) => string ;
62+ children : React . ReactNode ;
63+ } > ) ( {
64+ name : "rainbow" ,
65+ children : < Text > rainbow</ Text > ,
66+ } ) ;
67+
68+ assert . equal ( gradientElement . type , Transform ) ;
69+ assert . equal ( typeof gradientElement . props . transform , "function" ) ;
70+
71+ const frame = await renderToLastFrameBytes (
72+ < Gradient name = "rainbow" >
73+ < Text > rainbow</ Text >
74+ </ Gradient > ,
75+ ) ;
6176
62- return < Transform transform = { transform } > { props . children } </ Transform > ;
63- }
77+ assert . ok ( frame . length > 0 ) ;
78+ } ) ;
6479
80+ test ( "third-party components remain compatible with scroll measurement semantics" , async ( ) => {
6581 const backend = new StubBackend ( ) ;
82+ const containerRef = React . createRef < DOMElement > ( ) ;
83+
6684 const inst = render (
67- < GradientLike >
68- < Text > rainbow</ Text >
69- </ GradientLike > ,
85+ < Box
86+ ref = { containerRef }
87+ width = { 20 }
88+ height = { 1 }
89+ flexDirection = "column"
90+ overflowY = "scroll"
91+ overflowX = "hidden"
92+ scrollTop = { 1 }
93+ >
94+ < Spinner type = "line" />
95+ < Gradient name = "pastel" >
96+ < Text > line-2</ Text >
97+ </ Gradient >
98+ < Text > line-3</ Text >
99+ </ Box > ,
70100 { internal_backend : backend , exitOnCtrlC : false } ,
71101 ) ;
72102
73103 await flushMicrotasks ( 10 ) ;
74104 await pushInitialResize ( backend ) ;
75105
76- assert . equal ( lastInput , "rainbow" ) ;
106+ const container = containerRef . current ;
107+ assert . ok ( container ) ;
108+ assert . equal ( getInnerHeight ( container ) , 1 ) ;
109+ assert . ok ( getScrollHeight ( container ) >= 3 ) ;
77110 assert . ok ( backend . requestedFrames . length >= 1 ) ;
78111
79112 inst . unmount ( ) ;
0 commit comments