@@ -1637,6 +1637,85 @@ tap.test('bins are installed', async t => {
16371637 t . ok ( binFromBarToWhich )
16381638} )
16391639
1640+ tap . test ( 'orphaned store entries are cleaned up on dependency update' , async t => {
1641+ const graph = {
1642+ registry : [
1643+ { name : 'which' , version : '1.0.0' , dependencies : { isexe : '^1.0.0' } } ,
1644+ { name : 'which' , version : '2.0.0' , dependencies : { isexe : '^1.0.0' } } ,
1645+ { name : 'isexe' , version : '1.0.0' } ,
1646+ ] ,
1647+ root : {
1648+ name : 'myproject' ,
1649+ version : '1.0.0' ,
1650+ dependencies : { which : '1.0.0' } ,
1651+ } ,
1652+ }
1653+ const { dir, registry } = await getRepo ( graph )
1654+ const cache = fs . mkdtempSync ( `${ getTempDir ( ) } /test-` )
1655+ const storeDir = path . join ( dir , 'node_modules' , '.store' )
1656+
1657+ // First install — which@1.0.0
1658+ const arb1 = new Arborist ( { path : dir , registry, packumentCache : new Map ( ) , cache } )
1659+ await arb1 . reify ( { installStrategy : 'linked' } )
1660+
1661+ const entriesAfterV1 = fs . readdirSync ( storeDir )
1662+ t . ok ( entriesAfterV1 . some ( e => e . startsWith ( 'which@1.0.0-' ) ) ,
1663+ 'store has which@1.0.0 entry after first install' )
1664+
1665+ // Update package.json to depend on which@2.0.0
1666+ const pkgPath = path . join ( dir , 'package.json' )
1667+ const pkg = JSON . parse ( fs . readFileSync ( pkgPath , 'utf8' ) )
1668+ pkg . dependencies . which = '2.0.0'
1669+ fs . writeFileSync ( pkgPath , JSON . stringify ( pkg ) )
1670+
1671+ // Second install — which@2.0.0
1672+ const arb2 = new Arborist ( { path : dir , registry, packumentCache : new Map ( ) , cache } )
1673+ await arb2 . reify ( { installStrategy : 'linked' } )
1674+
1675+ const entriesAfterV2 = fs . readdirSync ( storeDir )
1676+ t . ok ( entriesAfterV2 . some ( e => e . startsWith ( 'which@2.0.0-' ) ) ,
1677+ 'store has which@2.0.0 entry after update' )
1678+ t . notOk ( entriesAfterV2 . some ( e => e . startsWith ( 'which@1.0.0-' ) ) ,
1679+ 'old which@1.0.0 store entry is removed after update' )
1680+ } )
1681+
1682+ tap . test ( 'orphaned store entries are cleaned up on dependency removal' , async t => {
1683+ const graph = {
1684+ registry : [
1685+ { name : 'which' , version : '1.0.0' , dependencies : { isexe : '^1.0.0' } } ,
1686+ { name : 'isexe' , version : '1.0.0' } ,
1687+ ] ,
1688+ root : {
1689+ name : 'myproject' ,
1690+ version : '1.0.0' ,
1691+ dependencies : { which : '1.0.0' } ,
1692+ } ,
1693+ }
1694+ const { dir, registry } = await getRepo ( graph )
1695+ const cache = fs . mkdtempSync ( `${ getTempDir ( ) } /test-` )
1696+ const storeDir = path . join ( dir , 'node_modules' , '.store' )
1697+
1698+ // First install
1699+ const arb1 = new Arborist ( { path : dir , registry, packumentCache : new Map ( ) , cache } )
1700+ await arb1 . reify ( { installStrategy : 'linked' } )
1701+
1702+ t . ok ( fs . readdirSync ( storeDir ) . length > 0 , 'store has entries after install' )
1703+
1704+ // Remove the dependency
1705+ const pkgPath = path . join ( dir , 'package.json' )
1706+ const pkg = JSON . parse ( fs . readFileSync ( pkgPath , 'utf8' ) )
1707+ delete pkg . dependencies
1708+ fs . writeFileSync ( pkgPath , JSON . stringify ( pkg ) )
1709+
1710+ // Reinstall
1711+ const arb2 = new Arborist ( { path : dir , registry, packumentCache : new Map ( ) , cache } )
1712+ await arb2 . reify ( { installStrategy : 'linked' } )
1713+
1714+ const entriesAfterRemoval = fs . readdirSync ( storeDir )
1715+ t . equal ( entriesAfterRemoval . length , 0 ,
1716+ 'all store entries are removed when dependencies are removed' )
1717+ } )
1718+
16401719function setupRequire ( cwd ) {
16411720 return function requireChain ( ...chain ) {
16421721 return chain . reduce ( ( path , name ) => {
0 commit comments