1+ import { resolve } from 'node:path'
12import { beforeEach , describe , expect , it , vi } from 'vitest'
23import type { FeatureName } from '../../constants/config.js'
34
4- vi . mock ( '../../operations/exec.js' , ( ) => ( {
5- exec : vi . fn ( ) . mockResolvedValue ( undefined ) ,
6- execFile : vi . fn ( ) . mockResolvedValue ( undefined ) ,
5+ vi . mock ( 'node:fs/promises' , ( ) => ( {
6+ rm : vi . fn ( ) . mockResolvedValue ( undefined ) ,
7+ mkdir : vi . fn ( ) . mockResolvedValue ( undefined ) ,
8+ copyFile : vi . fn ( ) . mockResolvedValue ( undefined ) ,
79} ) )
810
911vi . mock ( 'node:fs' , ( ) => ( {
@@ -24,14 +26,23 @@ vi.mock('node:fs', () => ({
2426 writeFileSync : vi . fn ( ) ,
2527} ) )
2628
27- const { execFile } = await import ( '../../operations/exec.js ' )
29+ const { rm , mkdir , copyFile } = await import ( 'node:fs/promises ' )
2830const { readFileSync, writeFileSync } = await import ( 'node:fs' )
2931const { cleanupFiles } = await import ( '../../operations/cleanupFiles.js' )
3032
31- function getExecFileCommands ( ) : string [ ] {
32- return vi
33- . mocked ( execFile )
34- . mock . calls . map ( ( call ) => `${ call [ 0 ] } ${ ( call [ 1 ] as string [ ] ) . join ( ' ' ) } ` )
33+ function getRmPaths ( ) : string [ ] {
34+ return vi . mocked ( rm ) . mock . calls . map ( ( call ) => call [ 0 ] as string )
35+ }
36+
37+ function getMkdirPaths ( ) : string [ ] {
38+ return vi . mocked ( mkdir ) . mock . calls . map ( ( call ) => call [ 0 ] as string )
39+ }
40+
41+ function getCopyFileCalls ( ) : Array < { src : string ; dst : string } > {
42+ return vi . mocked ( copyFile ) . mock . calls . map ( ( call ) => ( {
43+ src : call [ 0 ] as string ,
44+ dst : call [ 1 ] as string ,
45+ } ) )
3546}
3647
3748function getWrittenPackageJson ( ) : Record < string , unknown > {
@@ -65,9 +76,8 @@ describe('cleanupFiles', () => {
6576 it ( 'only removes .install-files' , async ( ) => {
6677 await cleanupFiles ( '/project/my_app' , 'full' )
6778
68- const commands = getExecFileCommands ( )
69- expect ( commands ) . toHaveLength ( 1 )
70- expect ( commands [ 0 ] ) . toBe ( 'rm -rf .install-files' )
79+ expect ( rm ) . toHaveBeenCalledTimes ( 1 )
80+ expect ( getRmPaths ( ) [ 0 ] ) . toBe ( resolve ( '/project/my_app' , '.install-files' ) )
7181 } )
7282
7383 it ( 'does not patch package.json' , async ( ) => {
@@ -82,8 +92,8 @@ describe('cleanupFiles', () => {
8292 const allFeatures : FeatureName [ ] = [ 'demo' , 'subgraph' , 'typedoc' , 'vocs' , 'husky' ]
8393 await cleanupFiles ( '/project/my_app' , 'custom' , allFeatures )
8494
85- const commands = getExecFileCommands ( )
86- expect ( commands ) . toEqual ( [ 'rm -rf .install-files'] )
95+ expect ( rm ) . toHaveBeenCalledTimes ( 1 )
96+ expect ( getRmPaths ( ) [ 0 ] ) . toBe ( resolve ( '/project/my_app' , ' .install-files') )
8797 expect ( writeFileSync ) . toHaveBeenCalled ( )
8898 } )
8999
@@ -104,41 +114,47 @@ describe('cleanupFiles', () => {
104114 it ( 'removes home folder, recreates it, copies replacement' , async ( ) => {
105115 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'subgraph' , 'typedoc' , 'vocs' , 'husky' ] )
106116
107- const commands = getExecFileCommands ( )
108- expect ( commands ) . toContain ( 'rm -rf src/components/pageComponents/home' )
109- expect ( commands ) . toContain ( 'mkdir -p src/components/pageComponents/home' )
110- expect ( commands ) . toContain (
111- 'cp .install-files/home/index.tsx src/components/pageComponents/home/' ,
112- )
117+ const homeFolder = resolve ( '/project/my_app' , 'src/components/pageComponents/home' )
118+ expect ( getRmPaths ( ) ) . toContain ( homeFolder )
119+ expect ( getMkdirPaths ( ) ) . toContain ( homeFolder )
120+
121+ const copies = getCopyFileCalls ( )
122+ expect ( copies ) . toContainEqual ( {
123+ src : resolve ( '/project/my_app' , '.install-files/home/index.tsx' ) ,
124+ dst : resolve ( homeFolder , 'index.tsx' ) ,
125+ } )
113126 } )
114127 } )
115128
116129 describe ( 'custom mode — subgraph deselected' , ( ) => {
117130 it ( 'removes src/subgraphs' , async ( ) => {
118131 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' , 'typedoc' , 'vocs' , 'husky' ] )
119132
120- const commands = getExecFileCommands ( )
121- expect ( commands ) . toContain ( 'rm -rf src/subgraphs' )
133+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , 'src/subgraphs' ) )
122134 } )
123135
124136 it ( 'cleans up subgraph demos when demo IS selected' , async ( ) => {
125137 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' , 'typedoc' , 'vocs' , 'husky' ] )
126138
127- const commands = getExecFileCommands ( )
128- const homeFolder = 'src/components/pageComponents/home'
129- expect ( commands ) . toContain ( `rm -rf ${ homeFolder } /Examples/demos/subgraphs` )
130- expect ( commands ) . toContain ( `rm -f ${ homeFolder } /Examples/index.tsx` )
131- expect ( commands ) . toContain (
132- `cp .install-files/home/Examples/index.tsx ${ homeFolder } /Examples/index.tsx` ,
133- )
139+ const homeFolder = resolve ( '/project/my_app' , 'src/components/pageComponents/home' )
140+ expect ( getRmPaths ( ) ) . toContain ( resolve ( homeFolder , 'Examples/demos/subgraphs' ) )
141+ expect ( getRmPaths ( ) ) . toContain ( resolve ( homeFolder , 'Examples/index.tsx' ) )
142+
143+ const copies = getCopyFileCalls ( )
144+ expect ( copies ) . toContainEqual ( {
145+ src : resolve ( '/project/my_app' , '.install-files/home/Examples/index.tsx' ) ,
146+ dst : resolve ( homeFolder , 'Examples/index.tsx' ) ,
147+ } )
134148 } )
135149
136150 it ( 'does NOT clean up subgraph demos when demo is also deselected' , async ( ) => {
137151 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'typedoc' , 'vocs' , 'husky' ] )
138152
139- const commands = getExecFileCommands ( )
140- const demoCleanupCommands = commands . filter ( ( cmd ) => cmd . includes ( 'Examples/demos/subgraphs' ) )
141- expect ( demoCleanupCommands ) . toHaveLength ( 0 )
153+ const subgraphDemosPath = resolve (
154+ '/project/my_app' ,
155+ 'src/components/pageComponents/home/Examples/demos/subgraphs' ,
156+ )
157+ expect ( getRmPaths ( ) ) . not . toContain ( subgraphDemosPath )
142158 } )
143159
144160 it ( 'removes subgraph-codegen from package.json scripts' , async ( ) => {
@@ -154,8 +170,7 @@ describe('cleanupFiles', () => {
154170 it ( 'removes typedoc.json' , async ( ) => {
155171 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' , 'subgraph' , 'vocs' , 'husky' ] )
156172
157- const commands = getExecFileCommands ( )
158- expect ( commands ) . toContain ( 'rm -f typedoc.json' )
173+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , 'typedoc.json' ) )
159174 } )
160175
161176 it ( 'removes typedoc:build from package.json scripts' , async ( ) => {
@@ -171,9 +186,8 @@ describe('cleanupFiles', () => {
171186 it ( 'removes vocs.config.ts and docs folder' , async ( ) => {
172187 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' , 'subgraph' , 'typedoc' , 'husky' ] )
173188
174- const commands = getExecFileCommands ( )
175- expect ( commands ) . toContain ( 'rm -f vocs.config.ts' )
176- expect ( commands ) . toContain ( 'rm -rf docs' )
189+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , 'vocs.config.ts' ) )
190+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , 'docs' ) )
177191 } )
178192
179193 it ( 'removes docs scripts from package.json' , async ( ) => {
@@ -191,10 +205,9 @@ describe('cleanupFiles', () => {
191205 it ( 'removes husky folder and config files' , async ( ) => {
192206 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' , 'subgraph' , 'typedoc' , 'vocs' ] )
193207
194- const commands = getExecFileCommands ( )
195- expect ( commands ) . toContain ( 'rm -rf .husky' )
196- expect ( commands ) . toContain ( 'rm -f .lintstagedrc.mjs' )
197- expect ( commands ) . toContain ( 'rm -f commitlint.config.js' )
208+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , '.husky' ) )
209+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , '.lintstagedrc.mjs' ) )
210+ expect ( getRmPaths ( ) ) . toContain ( resolve ( '/project/my_app' , 'commitlint.config.js' ) )
198211 } )
199212
200213 it ( 'removes prepare from package.json scripts' , async ( ) => {
@@ -210,13 +223,13 @@ describe('cleanupFiles', () => {
210223 it ( 'runs all cleanup operations' , async ( ) => {
211224 await cleanupFiles ( '/project/my_app' , 'custom' , [ ] )
212225
213- const commands = getExecFileCommands ( )
214- expect ( commands ) . toContain ( 'rm -rf src/components/pageComponents/home')
215- expect ( commands ) . toContain ( 'rm -rf src/subgraphs')
216- expect ( commands ) . toContain ( 'rm -f typedoc.json')
217- expect ( commands ) . toContain ( 'rm -f vocs.config.ts')
218- expect ( commands ) . toContain ( 'rm -rf .husky')
219- expect ( commands ) . toContain ( 'rm -rf .install-files')
226+ const paths = getRmPaths ( )
227+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' src/components/pageComponents/home') )
228+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' src/subgraphs') )
229+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' typedoc.json') )
230+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' vocs.config.ts') )
231+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' .husky') )
232+ expect ( paths ) . toContain ( resolve ( '/project/my_app' , ' .install-files') )
220233 } )
221234
222235 it ( 'removes all optional scripts from package.json' , async ( ) => {
@@ -230,26 +243,24 @@ describe('cleanupFiles', () => {
230243 expect ( scripts [ 'docs:dev' ] ) . toBeUndefined ( )
231244 expect ( scripts [ 'docs:preview' ] ) . toBeUndefined ( )
232245 expect ( scripts . prepare ) . toBeUndefined ( )
233- // Preserved scripts
234246 expect ( scripts . dev ) . toBe ( 'next dev' )
235247 expect ( scripts . build ) . toBe ( 'next build' )
236248 } )
237249 } )
238250
239- it ( 'always removes .install-files as the last step ' , async ( ) => {
251+ it ( 'always removes .install-files as the last rm call ' , async ( ) => {
240252 await cleanupFiles ( '/project/my_app' , 'custom' , [ 'demo' ] )
241253
242- const commands = getExecFileCommands ( )
243- expect ( commands . at ( - 1 ) ) . toBe ( 'rm -rf .install-files')
254+ const paths = getRmPaths ( )
255+ expect ( paths . at ( - 1 ) ) . toBe ( resolve ( '/project/my_app' , ' .install-files') )
244256 } )
245257
246- it ( 'uses -f flag on all single-file rm calls for idempotent cleanup ' , async ( ) => {
258+ it ( 'uses force option on all rm calls' , async ( ) => {
247259 await cleanupFiles ( '/project/my_app' , 'custom' , [ ] )
248260
249- const commands = getExecFileCommands ( )
250- const rmCommands = commands . filter ( ( cmd ) => cmd . startsWith ( 'rm ' ) )
251- for ( const cmd of rmCommands ) {
252- expect ( cmd ) . toMatch ( / ^ r m - [ r f ] / )
261+ for ( const call of vi . mocked ( rm ) . mock . calls ) {
262+ const options = call [ 1 ] as { force ?: boolean }
263+ expect ( options . force ) . toBe ( true )
253264 }
254265 } )
255266
0 commit comments