@@ -2,12 +2,10 @@ import {LoadingBar} from './LoadingBar.js'
22import { Stdout } from '../../ui.js'
33import { render } from '../../testing/ui.js'
44import { shouldDisplayColors , unstyled } from '../../../../public/node/output.js'
5- import useLayout from '../hooks/use-layout.js'
6- import React from 'react'
5+ import React , { act } from 'react'
76
87import { beforeEach , describe , expect , test , vi } from 'vitest'
98
10- vi . mock ( '../hooks/use-layout.js' )
119vi . mock ( '../../../../public/node/output.js' , async ( ) => {
1210 const original : any = await vi . importActual ( '../../../../public/node/output.js' )
1311 return {
@@ -17,159 +15,88 @@ vi.mock('../../../../public/node/output.js', async () => {
1715} )
1816
1917beforeEach ( ( ) => {
20- vi . mocked ( useLayout ) . mockReturnValue ( {
21- twoThirds : 53 ,
22- oneThird : 27 ,
23- fullWidth : 80 ,
24- } )
2518 vi . mocked ( shouldDisplayColors ) . mockReturnValue ( true )
2619} )
2720
28- /**
29- * Creates a Stdout test double simulating a TTY stream.
30- * On real Node streams, isTTY is only present as an own property when the
31- * stream IS a TTY.
32- */
33- function createTTYStdout ( columns = 100 ) {
34- const stdout = new Stdout ( { columns} ) as Stdout & { isTTY : boolean }
21+ function createTTYStdout ( ) {
22+ const stdout = new Stdout ( { columns : 100 } ) as Stdout & { isTTY : boolean }
3523 stdout . isTTY = true
3624 return stdout
3725}
3826
39- /**
40- * Renders LoadingBar with a TTY stdout so the animated progress bar renders.
41- */
4227function renderWithTTY ( element : React . ReactElement ) {
4328 const stdout = createTTYStdout ( )
4429 const instance = render ( element , { stdout} )
4530 return { lastFrame : stdout . lastFrame , unmount : instance . unmount }
4631}
4732
4833describe ( 'LoadingBar' , ( ) => {
49- test ( 'renders loading bar with default colored characters' , async ( ) => {
50- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Loading content" /> )
51-
52- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
53- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
54- Loading content ..."
55- ` )
56- } )
34+ test ( 'renders the Shopify loading indicator' , async ( ) => {
35+ const { lastFrame, unmount} = renderWithTTY ( < LoadingBar title = "Loading content" /> )
36+ const frame = lastFrame ( ) !
5737
58- test ( 'renders loading bar with hill pattern when noColor prop is true' , async ( ) => {
59- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Processing files" noColor /> )
38+ expect ( unstyled ( frame ) ) . toBe ( 'S> Loading content ...' )
39+ expect ( frame ) . toContain ( '\u001B[1m' )
40+ expect ( frame ) . toContain ( '\u001B[3m' )
41+ expect ( frame ) . toContain ( '\u001B[38;2;150;191;72m' )
6042
61- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
62- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
63- Processing files ..."
64- ` )
43+ unmount ( )
6544 } )
6645
67- test ( 'renders loading bar with hill pattern when shouldDisplayColors returns false' , async ( ) => {
68- vi . mocked ( shouldDisplayColors ) . mockReturnValue ( false )
69- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Downloading packages" /> )
70-
71- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
72- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
73- Downloading packages ..."
74- ` )
75- } )
46+ test ( 'blinks the chevron without shifting the title' , async ( ) => {
47+ vi . useFakeTimers ( )
48+ const { lastFrame, unmount} = renderWithTTY ( < LoadingBar title = "Uploading theme" /> )
7649
77- test ( 'handles narrow terminal width correctly' , async ( ) => {
78- vi . mocked ( useLayout ) . mockReturnValue ( { twoThirds : 20 , oneThird : 10 , fullWidth : 30 } )
79- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Building app" /> )
50+ try {
51+ await act ( async ( ) => {
52+ await vi . advanceTimersByTimeAsync ( 350 )
53+ } )
8054
81- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
82- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
83- Building app ..."
84- ` )
55+ expect ( unstyled ( lastFrame ( ) ! ) ) . toBe ( 'S Uploading theme ...' )
56+ } finally {
57+ unmount ( )
58+ vi . useRealTimers ( )
59+ }
8560 } )
8661
87- test ( 'handles narrow terminal width correctly in no-color mode' , async ( ) => {
88- vi . mocked ( useLayout ) . mockReturnValue ( { twoThirds : 15 , oneThird : 8 , fullWidth : 23 } )
89- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Installing" noColor /> )
90-
91- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
92- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇
93- Installing ..."
94- ` )
95- } )
62+ test ( 'renders the chevron without color when noColor is true' , async ( ) => {
63+ const { lastFrame, unmount} = renderWithTTY ( < LoadingBar title = "Processing files" noColor /> )
64+ const frame = lastFrame ( ) !
9665
97- test ( 'handles very narrow terminal width in no-color mode' , async ( ) => {
98- vi . mocked ( useLayout ) . mockReturnValue ( { twoThirds : 5 , oneThird : 3 , fullWidth : 8 } )
99- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Wait" noColor /> )
66+ expect ( unstyled ( frame ) ) . toBe ( 'S> Processing files ...' )
67+ expect ( frame ) . not . toContain ( '\u001B[38;2;150;191;72m' )
10068
101- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
102- "▁▁▁▂▂
103- Wait ..."
104- ` )
69+ unmount ( )
10570 } )
10671
107- test ( 'handles wide terminal width correctly' , async ( ) => {
108- vi . mocked ( useLayout ) . mockReturnValue ( { twoThirds : 100 , oneThird : 50 , fullWidth : 150 } )
109- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Synchronizing data" /> )
110-
111- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
112- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
113- Synchronizing data ..."
114- ` )
115- } )
72+ test ( 'renders the chevron without color when colors are disabled' , async ( ) => {
73+ vi . mocked ( shouldDisplayColors ) . mockReturnValue ( false )
74+ const { lastFrame, unmount} = renderWithTTY ( < LoadingBar title = "Downloading packages" /> )
75+ const frame = lastFrame ( ) !
11676
117- test ( 'handles wide terminal width correctly in no-color mode with pattern repetition' , async ( ) => {
118- vi . mocked ( useLayout ) . mockReturnValue ( { twoThirds : 90 , oneThird : 45 , fullWidth : 135 } )
119- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Analyzing dependencies" noColor /> )
77+ expect ( unstyled ( frame ) ) . toBe ( 'S> Downloading packages ...' )
78+ expect ( frame ) . not . toContain ( '\u001B[38;2;150;191;72m' )
12079
121- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
122- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁
123- Analyzing dependencies ..."
124- ` )
80+ unmount ( )
12581 } )
12682
127- test ( 'renders correctly with empty title' , async ( ) => {
128- const { lastFrame} = renderWithTTY ( < LoadingBar title = "" /> )
129-
130- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
131- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
132- ..."
133- ` )
134- } )
83+ test ( 'renders correctly with an empty title' , async ( ) => {
84+ const { lastFrame, unmount} = renderWithTTY ( < LoadingBar title = "" /> )
13585
136- test ( 'noColor prop overrides shouldDisplayColors when both would show colors' , async ( ) => {
137- vi . mocked ( shouldDisplayColors ) . mockReturnValue ( true )
138- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Testing override" noColor /> )
86+ expect ( unstyled ( lastFrame ( ) ! ) ) . toBe ( 'S> ...' )
13987
140- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `
141- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
142- Testing override ..."
143- ` )
88+ unmount ( )
14489 } )
14590
146- test ( 'renders consistently with same props' , async ( ) => {
147- const props = { title : 'Consistent test' , noColor : false }
148- const { lastFrame : frame1 } = renderWithTTY ( < LoadingBar { ...props } /> )
149- const { lastFrame : frame2 } = renderWithTTY ( < LoadingBar { ...props } /> )
150-
151- expect ( frame1 ( ) ) . toBe ( frame2 ( ) )
152- } )
153-
154- test ( 'hides progress bar when noProgressBar is true' , async ( ) => {
155- vi . mocked ( shouldDisplayColors ) . mockReturnValue ( true )
91+ test ( 'hides the loading indicator when noProgressBar is true' , async ( ) => {
15692 const { lastFrame} = renderWithTTY ( < LoadingBar title = "task 1" noProgressBar /> )
15793
158- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `" task 1 ..."` )
94+ expect ( unstyled ( lastFrame ( ) ! ) ) . toBe ( ' task 1 ...' )
15995 } )
16096
16197 test ( 'shows only static title text when output stream is not a TTY' , async ( ) => {
162- // Default test Stdout has no isTTY property, simulating a non-TTY stream
16398 const { lastFrame} = render ( < LoadingBar title = "Installing dependencies" /> )
16499
165- expect ( unstyled ( lastFrame ( ) ! ) ) . toMatchInlineSnapshot ( `"Installing dependencies ..."` )
166- } )
167-
168- test ( 'shows animated progress bar when output stream is a TTY' , async ( ) => {
169- const { lastFrame} = renderWithTTY ( < LoadingBar title = "Uploading theme" /> )
170-
171- const frame = unstyled ( lastFrame ( ) ! )
172- expect ( frame ) . toContain ( '▀' )
173- expect ( frame ) . toContain ( 'Uploading theme ...' )
100+ expect ( unstyled ( lastFrame ( ) ! ) ) . toBe ( 'Installing dependencies ...' )
174101 } )
175102} )
0 commit comments