2021-02-19 04:31:33 +00:00
import { promises as fs } from 'fs'
import { tmpdir } from 'os'
import { join , resolve } from 'path'
2020-12-13 00:18:25 +00:00
2021-06-05 15:29:15 +00:00
import packwatch from '../src'
2023-03-22 04:15:39 +00:00
import type { Report } from '../src/types'
2021-06-05 15:29:15 +00:00
let workspace : string | null
2020-12-13 00:18:25 +00:00
2023-03-22 04:15:39 +00:00
function getActualPackageSizeByNodeVersion ( nodeVersion : string ) : string {
2023-03-26 15:42:59 +00:00
if ( nodeVersion . startsWith ( 'v14' ) ) return '160'
else if ( nodeVersion . startsWith ( 'v16' ) ) return '157'
else if ( nodeVersion . startsWith ( 'v18' ) ) return '157'
2023-03-22 04:15:39 +00:00
2023-03-26 15:42:59 +00:00
return 'unknown'
2023-03-22 04:15:39 +00:00
}
2021-02-19 04:31:33 +00:00
async function prepareWorkspace ( ) : Promise < string > {
2023-03-26 15:42:59 +00:00
const workspacePath = await fs . mkdtemp ( ` ${ tmpdir ( ) } / ` )
workspace = workspacePath
return workspacePath
2020-12-13 00:18:25 +00:00
}
2021-02-19 04:31:33 +00:00
async function cleanUpWorkspace ( paths : string [ ] ) : Promise < void > {
2023-03-26 15:42:59 +00:00
await Promise . all ( paths . map ( async ( path ) = > fs . rmdir ( path , { recursive : true } ) ) )
2020-12-13 00:18:25 +00:00
}
2021-02-19 04:31:33 +00:00
async function createFile ( path : string , content : string ) : Promise < void > {
2023-03-26 15:42:59 +00:00
await fs . writeFile ( path , content )
2021-02-19 04:31:33 +00:00
}
async function createPackageJson ( cwd : string ) : Promise < void > {
2023-03-26 15:42:59 +00:00
const path = resolve ( join ( cwd , 'package.json' ) )
await createFile ( path , '{ "name": "wow", "version": "0.0.0", "files": ["!.packwatch.json"] }' )
2021-02-19 04:31:33 +00:00
}
2023-03-26 15:42:59 +00:00
async function createManifest ( cwd : string , configuration : Report ) : Promise < void > {
const path = resolve ( join ( cwd , '.packwatch.json' ) )
await createFile ( path , JSON . stringify ( configuration ) )
2020-12-13 00:18:25 +00:00
}
2021-06-05 15:29:15 +00:00
describe ( 'Packwatch' , ( ) = > {
2023-03-26 15:42:59 +00:00
const actualSize = getActualPackageSizeByNodeVersion ( process . version )
afterEach ( async ( ) = > {
jest . restoreAllMocks ( )
if ( workspace ) {
await cleanUpWorkspace ( [ workspace ] )
workspace = null
}
} )
it ( 'warns the user and errors if run away from package.json' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await expect ( async ( ) = > packwatch ( { cwd : workspacePath } ) ) . rejects . toThrow ( 'NOT_IN_PACKAGE_ROOT' )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching ( 'There is no package.json file here. Are you in the root directory of your project?' ) ,
)
} )
describe ( 'without manifest' , ( ) = > {
it ( 'generates the initial manifest properly' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
await createPackageJson ( workspacePath )
await expect ( async ( ) = > packwatch ( { cwd : workspacePath } ) ) . rejects . toThrow ( 'NO_MANIFEST_NO_UPDATE' )
const generatedManifest = await fs . readFile ( resolve ( join ( workspacePath , '.packwatch.json' ) ) , { encoding : 'utf8' } )
expect ( generatedManifest ) . toBe (
` {"limit":" ${ actualSize } B","packageSize":" ${ actualSize } B","unpackedSize":"68 B"} ` ,
)
} )
it ( 'outputs expected messaging' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockWarn = jest . spyOn ( console , 'warn' )
const mockError = jest . spyOn ( console , 'error' )
await createPackageJson ( workspacePath )
await expect ( async ( ) = > packwatch ( { cwd : workspacePath } ) ) . rejects . toThrow ( )
expect ( mockWarn . mock . calls ) . toHaveLength ( 1 )
expect ( mockWarn . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching (
/No Manifest to compare against! Current package stats written to \.packwatch\.json!\nPackage size \(\d+ B\) adopted as new limit\./ ,
) ,
)
expect ( mockError . mock . calls ) . toHaveLength ( 1 )
expect ( mockError . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching (
'It looks like you ran PackWatch without a manifest. To prevent accidental passes in CI or hooks, packwatch will terminate with an error. If you are running packwatch for the first time in your project, this is expected!' ,
) ,
)
} )
it ( 'outputs expected messaging when not updating the manifest' , async ( ) = > {
const mockWarn = jest . spyOn ( console , 'warn' )
const workspacePath = await prepareWorkspace ( )
await createPackageJson ( workspacePath )
await packwatch ( { cwd : workspacePath , isUpdatingManifest : true } )
expect ( mockWarn . mock . calls ) . toHaveLength ( 1 )
expect ( mockWarn . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching (
/No Manifest to compare against! Current package stats written to \.packwatch\.json!\nPackage size \(\d+ B\) adopted as new limit\./ ,
) ,
)
} )
} )
describe ( 'with manifest' , ( ) = > {
it ( 'messages when the size is equal to the limit' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : ` ${ actualSize } B ` ,
packageSize : ` ${ actualSize } B ` ,
packageSizeBytes : Number ( actualSize ) ,
unpackedSize : '150B' ,
unpackedSizeBytes : 150 ,
} )
await packwatch ( { cwd : workspacePath } )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching ( /Nothing to report! Your package is the same size as the latest manifest reports!/ ) ,
)
} )
it ( 'messages when the size is lower than the limit (no growth)' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : '170B' ,
packageSize : ` ${ actualSize } B ` ,
packageSizeBytes : Number ( actualSize ) ,
unpackedSize : '150B' ,
unpackedSizeBytes : 150 ,
} )
await packwatch ( { cwd : workspacePath } )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching (
/Nothing to report! Your package is the same size as the latest manifest reports! \(Limit: 170B\)/ ,
) ,
)
} )
it ( 'messages when the size is lower than the limit (growth)' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : '180B' ,
packageSize : '150B' ,
packageSizeBytes : 150 ,
unpackedSize : '140B' ,
unpackedSizeBytes : 140 ,
} )
await packwatch ( { cwd : workspacePath } )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching ( /Your package grew! \d+ B > 150B \(Limit: 180B\)/ ) ,
)
} )
it ( 'messages when the size is lower than the limit (shrinkage)' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : '180B' ,
packageSize : '170B' ,
packageSizeBytes : 170 ,
unpackedSize : '140B' ,
unpackedSizeBytes : 140 ,
} )
await packwatch ( { cwd : workspacePath } )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching ( /Your package shrank! \d+ B < 170B \(Limit: 180B\)/ ) ,
)
} )
it ( 'messages when the size exceeds the limit' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockError = jest . spyOn ( console , 'error' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : '10B' ,
packageSize : '170B' ,
packageSizeBytes : 170 ,
unpackedSize : '140B' ,
unpackedSizeBytes : 140 ,
} )
await expect ( async ( ) = > packwatch ( { cwd : workspacePath } ) ) . rejects . toThrow ( 'PACKAGE_EXCEEDS_LIMIT' )
expect ( mockError . mock . calls ) . toHaveLength ( 1 )
expect ( mockError . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching (
/Your package exceeds the limit set in \.packwatch\.json! \d+ B > 10B\nEither update the limit by using the --update-manifest flag or trim down your packed files!/ ,
) ,
)
} )
it ( 'messages when updating the manifest' , async ( ) = > {
const workspacePath = await prepareWorkspace ( )
const mockLogger = jest . spyOn ( console , 'log' )
await createPackageJson ( workspacePath )
await createManifest ( workspacePath , {
limit : '10B' ,
packageSize : '170B' ,
packageSizeBytes : 170 ,
unpackedSize : '140B' ,
unpackedSizeBytes : 140 ,
} )
await packwatch ( { cwd : workspacePath , isUpdatingManifest : true } )
expect ( mockLogger . mock . calls ) . toHaveLength ( 1 )
expect ( mockLogger . mock . calls [ 0 ] [ 0 ] ) . toEqual (
expect . stringMatching ( /Updated the manifest! Package size: \d+ B, Limit: \d+ B/ ) ,
)
} )
} )
2020-12-13 00:18:25 +00:00
} )