@@ -2,7 +2,7 @@ import Bun from 'bun';
22
33import { version } from '../package.json' ;
44
5- import { test , expect , afterEach } from 'bun:test' ;
5+ import { test , expect } from 'bun:test' ;
66import * as path from 'node:path' ;
77import * as fs from 'node:fs/promises' ;
88
@@ -51,7 +51,8 @@ const packageManagers = process.env.ALL_PACKAGE_MANAGERS
5151
5252const skipSnapshots = process . env . SKIP_SNAPSHOTS === '1' ;
5353const shouldSkipInstallsInTests = process . platform === 'win32' ;
54- let currentProjectName = 'myTestProject' ;
54+ const retryableCleanupErrorCodes = new Set ( [ 'EBUSY' , 'EPERM' , 'ENOTEMPTY' ] ) ;
55+ const snapshotIgnoredEntries = new Set ( [ 'bun.lock' , 'bun.lockb' , 'package-lock.json' , 'pnpm-lock.yaml' , 'yarn.lock' ] ) ;
5556
5657test ( `outputs version` , async ( ) => {
5758 const output = await cli ( [ `--version` ] ) ;
@@ -110,15 +111,13 @@ const popularCombinations = [
110111 ...reactNavigationCombinations
111112] ;
112113
113- const getPathToProject = ( ) => `./${ currentProjectName } ` ;
114-
115- const cleanupProject = async ( ) => {
114+ const cleanupProject = async ( pathToProject : string ) => {
116115 for ( let attempt = 0 ; attempt < 5 ; attempt ++ ) {
117116 try {
118- await fs . rm ( getPathToProject ( ) , { recursive : true , force : true } ) ;
117+ await fs . rm ( pathToProject , { recursive : true , force : true } ) ;
119118 return ;
120119 } catch ( error ) {
121- if ( ( error as NodeJS . ErrnoException ) . code !== 'EBUSY' || attempt === 4 ) {
120+ if ( ! retryableCleanupErrorCodes . has ( ( error as NodeJS . ErrnoException ) . code ?? '' ) || attempt === 4 ) {
122121 throw error ;
123122 }
124123
@@ -127,30 +126,25 @@ const cleanupProject = async () => {
127126 }
128127} ;
129128
130- afterEach ( async ( ) => {
131- await cleanupProject ( ) ;
132- } ) ;
133-
134- const listProjectFiles = async ( dir : string , displayPath : string ) : Promise < string [ ] > => {
129+ const listProjectFiles = async ( dir : string , displayPath : string , pathToProject : string ) : Promise < string [ ] > => {
135130 const entries = await fs . readdir ( dir , { withFileTypes : true } ) ;
136131 const files : string [ ] = [ ] ;
137132
138133 for ( const entry of entries ) {
139134 const childDisplayPath = `${ displayPath } /${ entry . name } ` ;
140135
141136 if (
142- childDisplayPath . startsWith ( `${ getPathToProject ( ) } /node_modules` ) ||
143- childDisplayPath . startsWith ( `${ getPathToProject ( ) } /.git` ) ||
144- entry . name === 'bun.lock' ||
145- entry . name === 'bun.lockb'
137+ childDisplayPath . startsWith ( `${ pathToProject } /node_modules` ) ||
138+ childDisplayPath . startsWith ( `${ pathToProject } /.git` ) ||
139+ snapshotIgnoredEntries . has ( entry . name )
146140 ) {
147141 continue ;
148142 }
149143
150144 files . push ( childDisplayPath ) ;
151145
152146 if ( entry . isDirectory ( ) ) {
153- files . push ( ...( await listProjectFiles ( path . join ( dir , entry . name ) , childDisplayPath ) ) ) ;
147+ files . push ( ...( await listProjectFiles ( path . join ( dir , entry . name ) , childDisplayPath , pathToProject ) ) ) ;
154148 }
155149 }
156150
@@ -167,84 +161,88 @@ for (const packageManager of packageManagers) {
167161 : requestedFlags ;
168162
169163 test ( `generates a project with ${ requestedFlags . join ( ' ' ) } ` , async ( ) => {
170- currentProjectName = `myTestProject-${ packageManager } -${ index } ` ;
171- const pathToProject = getPathToProject ( ) ;
164+ const projectName = `myTestProject-${ packageManager } -${ index } ` ;
165+ const pathToProject = `./ ${ projectName } ` ;
172166
173- const output = await generateProject ( {
174- projectName : currentProjectName ,
175- flags : effectiveFlags
176- } ) ;
167+ try {
168+ const output = await generateProject ( {
169+ projectName,
170+ flags : effectiveFlags
171+ } ) ;
177172
178- expect ( output ) . toContain ( packageManager ) ;
173+ expect ( output ) . toContain ( packageManager ) ;
179174
180- if ( ! effectiveFlags . includes ( '--no-install' ) ) {
181- expect ( output ) . toContain ( 'Installing dependencies' ) ;
182- }
175+ if ( ! effectiveFlags . includes ( '--no-install' ) ) {
176+ expect ( output ) . toContain ( 'Installing dependencies' ) ;
177+ }
183178
184- const pkgjson = await Bun . file ( `${ pathToProject } /package.json` ) . json ( ) ;
185-
186- const pkgJsonWithoutVersions = {
187- ...pkgjson ,
188- name : 'myTestProject' ,
189- dependencies : Object . keys ( pkgjson . dependencies ) . reduce ( ( acc , key ) => {
190- return {
191- ...acc ,
192- [ key ] : ''
193- } ;
194- } , { } ) ,
195- devDependencies : Object . keys ( pkgjson . devDependencies ) . reduce ( ( acc , key ) => {
196- return {
197- ...acc ,
198- [ key ] : ''
199- } ;
200- } , { } )
201- } ;
202-
203- if ( ! skipSnapshots ) {
204- expect ( pkgJsonWithoutVersions ) . toMatchSnapshot ( `${ requestedFlags . join ( ', ' ) } -package-json` ) ;
205- }
179+ const pkgjson = await Bun . file ( `${ pathToProject } /package.json` ) . json ( ) ;
180+
181+ const pkgJsonWithoutVersions = {
182+ ...pkgjson ,
183+ name : 'myTestProject' ,
184+ dependencies : Object . keys ( pkgjson . dependencies ) . reduce ( ( acc , key ) => {
185+ return {
186+ ...acc ,
187+ [ key ] : ''
188+ } ;
189+ } , { } ) ,
190+ devDependencies : Object . keys ( pkgjson . devDependencies ) . reduce ( ( acc , key ) => {
191+ return {
192+ ...acc ,
193+ [ key ] : ''
194+ } ;
195+ } , { } )
196+ } ;
197+
198+ if ( ! skipSnapshots ) {
199+ expect ( pkgJsonWithoutVersions ) . toMatchSnapshot ( `${ requestedFlags . join ( ', ' ) } -package-json` ) ;
200+ }
206201
207- const cesconfigText = await Bun . file ( `${ pathToProject } /cesconfig.jsonc` ) . text ( ) ;
208- // Strip single-line comments from JSONC
209- const cleanedText = cesconfigText . replace ( / ^ \s * \/ \/ .* $ / gm, '' ) ;
210- const cesconfig = JSON . parse ( cleanedText ) ;
211-
212- const cesconfigWithoutOS = {
213- ...cesconfig ,
214- projectName : 'myTestProject' ,
215- cesVersion : undefined ,
216- os : { } ,
217- packageManager : { ...cesconfig . packageManager , version : undefined } ,
218- flags : {
219- ...cesconfig . flags ,
220- noInstall : requestedFlags . includes ( '--no-install' ) ,
221- publish : false
202+ const cesconfigText = await Bun . file ( `${ pathToProject } /cesconfig.jsonc` ) . text ( ) ;
203+ // Strip single-line comments from JSONC
204+ const cleanedText = cesconfigText . replace ( / ^ \s * \/ \/ .* $ / gm, '' ) ;
205+ const cesconfig = JSON . parse ( cleanedText ) ;
206+
207+ const cesconfigWithoutOS = {
208+ ...cesconfig ,
209+ projectName : 'myTestProject' ,
210+ cesVersion : undefined ,
211+ os : { } ,
212+ packageManager : { ...cesconfig . packageManager , version : undefined } ,
213+ flags : {
214+ ...cesconfig . flags ,
215+ noInstall : requestedFlags . includes ( '--no-install' ) ,
216+ publish : false
217+ }
218+ } ;
219+
220+ if ( ! skipSnapshots ) {
221+ expect ( cesconfigWithoutOS ) . toMatchSnapshot ( `${ requestedFlags . join ( ', ' ) } -ces-config-json` ) ;
222222 }
223- } ;
224223
225- if ( ! skipSnapshots ) {
226- expect ( cesconfigWithoutOS ) . toMatchSnapshot ( `${ requestedFlags . join ( ', ' ) } -ces-config-json` ) ;
227- }
224+ // sort the file list for consistent snapshotting
225+ const sortedFileList = [ pathToProject , ...( await listProjectFiles ( pathToProject , pathToProject , pathToProject ) ) ]
226+ . map ( ( filePath ) => filePath . replaceAll ( projectName , 'myTestProject' ) )
227+ . toSorted ( ( a , b ) => a . localeCompare ( b , 'en' , { sensitivity : 'base' } ) ) ;
228228
229- // sort the file list for consistent snapshotting
230- const sortedFileList = [ pathToProject , ...( await listProjectFiles ( pathToProject , pathToProject ) ) ]
231- . map ( ( filePath ) => filePath . replaceAll ( currentProjectName , 'myTestProject' ) )
232- . toSorted ( ( a , b ) => a . localeCompare ( b , 'en' , { sensitivity : 'base' } ) ) ;
229+ if ( ! skipSnapshots ) {
230+ expect ( sortedFileList ) . toMatchSnapshot ( `${ requestedFlags . join ( ', ' ) } -file-list` ) ;
231+ }
233232
234- if ( ! skipSnapshots ) {
235- expect ( sortedFileList ) . toMatchSnapshot ( ` ${ requestedFlags . join ( ', ' ) } -file-list` ) ;
236- }
233+ // typecheck only works if we have packages installed
234+ if ( ! effectiveFlags . includes ( '--no-install' ) ) {
235+ const { stderr , stdout , exitCode } = await Bun . $ `cd ${ projectName } && bun run tsc --noEmit` ;
237236
238- // typecheck only works if we have packages installed
239- if ( ! effectiveFlags . includes ( '--no-install' ) ) {
240- const { stderr, stdout, exitCode } = await Bun . $ `cd ${ currentProjectName } && bun run tsc --noEmit` ;
237+ if ( exitCode !== 0 ) {
238+ console . warn ( 'stdout' , stdout . toString ( ) ) ;
239+ console . warn ( 'stderr' , stderr . toString ( ) ) ;
240+ }
241241
242- if ( exitCode !== 0 ) {
243- console . warn ( 'stdout' , stdout . toString ( ) ) ;
244- console . warn ( 'stderr' , stderr . toString ( ) ) ;
242+ expect ( exitCode ) . toBe ( 0 ) ;
245243 }
246-
247- expect ( exitCode ) . toBe ( 0 ) ;
244+ } finally {
245+ await cleanupProject ( pathToProject ) ;
248246 }
249247 } ) ;
250248 }
0 commit comments