hunk.code_window:   const orphanDepPaths = R.difference(oldDepPaths, newDepPaths)
     const orphanPkgIds = new Set(R.props<string, string>(orphanDepPaths, oldPkgIdsByDepPaths))
     statsLogger.debug({removed: orphanPkgIds.size})
     if (!opts.dryRun) {
       if (orphanDepPaths.length) {
  
hunk.labels: keep keep keep replace keep keep keep
hunk.after_edit:   statsLogger.debug({
       prefix: opts.prefix,
       removed: orphanPkgIds.size,
     })
  
hunk.file_path: src/api/removeOrphanPkgs.ts
hunk.type: replace
file: import 'sepia'
  import tape = require('tape')
  import promisifyTape from 'tape-promise'
  const test = promisifyTape(tape)
  import caw = require('caw')
  import crossSpawn = require('cross-spawn')
  import fs = require('mz/fs')
  import path = require('path')
  import semver = require('semver')
  const spawnSync = crossSpawn.sync
  import isCI = require('is-ci')
  import loadJsonFile = require('load-json-file')
  import readPkg = require('read-pkg')
  import rimraf = require('rimraf-then')
  import {
    addDistTag,
    prepare,
    testDefaults,
  } from '../utils'
  const basicPackageJson = loadJsonFile.sync(path.join(__dirname, '../utils/simple-package.json'))
  import deepRequireCwd = require('deep-require-cwd')
  import isWindows = require('is-windows')
  import exists = require('path-exists')
  import sinon = require('sinon')
  import {install, installPkgs, uninstall} from 'supi'
  import {
    PackageJsonLog,
    ProgressLog,
    RootLog,
    StageLog,
    StatsLog,
  } from 'supi'
  import writeJsonFile = require('write-json-file')
  
  const IS_WINDOWS = isWindows()
  
  if (!caw() && !IS_WINDOWS) {
    process.env.VCR_MODE = 'cache'
  }
  
  test('small with dependencies (rimraf)', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['rimraf@2.5.1'], await testDefaults())
  
    const m = project.requireModule('rimraf')
    t.ok(typeof m === 'function', 'rimraf() is available')
    await project.isExecutable('.bin/rimraf')
  })
  
  test('ignoring some files in the dependency', async (t: tape.Test) => {
    const project = prepare(t)
  
    const ignoreFile = (filename: string) => filename === 'readme.md'
    await installPkgs(['is-positive@1.0.0'], await testDefaults({}, {}, {ignoreFile}))
  
    t.ok(await exists(path.resolve('node_modules', 'is-positive', 'package.json')), 'package.json was not ignored')
    t.notOk(await exists(path.resolve('node_modules', 'is-positive', 'readme.md')), 'readme.md was ignored')
  })
  
  test('no dependencies (lodash)', async (t: tape.Test) => {
    const project = prepare(t)
    const reporter = sinon.spy()
  
    await addDistTag('lodash', '4.1.0', 'latest')
  
    await installPkgs(['lodash@4.0.0'], await testDefaults({reporter}))
  
    t.ok(reporter.calledWithMatch({
      initial: {name: 'project', version: '0.0.0'},
      level: 'debug',
      name: 'pnpm:package-json',
    } as PackageJsonLog), 'initial package.json logged')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      message: 'resolution_started',
      name: 'pnpm:stage',
    } as StageLog), 'resolution stage start logged')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      message: 'resolution_done',
      name: 'pnpm:stage',
    } as StageLog), 'resolution stage done logged')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      message: 'importing_started',
      name: 'pnpm:stage',
    } as StageLog), 'importing stage start logged')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      message: 'importing_done',
      name: 'pnpm:stage',
    } as StageLog), 'importing stage done logged')
    // Not logged for now
    // t.ok(reporter.calledWithMatch({
    //   level: 'info',
    //   message: 'Creating dependency graph',
    // }), 'informed about creating dependency graph')
    t.ok(reporter.calledWithMatch({
      added: 1,
      level: 'debug',
      name: 'pnpm:stats',
    } as StatsLog), 'added stat')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      name: 'pnpm:stats',
      removed: 0,
   } as StatsLog), 'removed stat')
    t.ok(reporter.calledWithMatch({
      added: {
        dependencyType: 'prod',
        latest: '4.1.0',
        name: 'lodash',
        realName: 'lodash',
        version: '4.0.0',
      },
      level: 'info',
      name: 'pnpm:root',
    } as RootLog), 'added to root')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      name: 'pnpm:package-json',
      updated: {
        dependencies: {
          lodash: '^4.0.0',
        },
        name: 'project',
        version: '0.0.0',
      },
    } as PackageJsonLog), 'updated package.json logged')
  
    const m = project.requireModule('lodash')
    t.ok(typeof m === 'function', '_ is available')
    t.ok(typeof m.clone === 'function', '_.clone is available')
  })
  
  test('scoped modules without version spec (@rstacruz/tap-spec)', async (t) => {
    const project = prepare(t)
    await installPkgs(['@rstacruz/tap-spec'], await testDefaults())
  
    const m = project.requireModule('@rstacruz/tap-spec')
    t.ok(typeof m === 'function', 'tap-spec is available')
  })
  
  test('scoped package with custom registry', async (t) => {
    const project = prepare(t)
  
    await installPkgs(['@scoped/peer'], await testDefaults({
      // setting an incorrect default registry URL
      rawNpmConfig: {
        '@scoped:registry': 'http://localhost:4873/',
      },
      registry: 'http://localhost:9999/',
    }))
  
    const m = project.requireModule('@scoped/peer/package.json')
    t.ok(m, 'is available')
  })
  
  test('modules without version spec, with custom tag config', async (t) => {
    const project = prepare(t)
  
    const tag = 'beta'
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', tag)
  
    await installPkgs(['dep-of-pkg-with-1-dep'], await testDefaults({tag}))
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  })
  
  test('installing a package by specifying a specific dist-tag', async (t) => {
    const project = prepare(t)
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', 'beta')
  
    await installPkgs(['dep-of-pkg-with-1-dep@beta'], await testDefaults())
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  })
  
  test('update a package when installing with a dist-tag', async (t: tape.Test) => {
    const project = prepare(t)
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', 'latest')
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'beta')
  
    await installPkgs(['dep-of-pkg-with-1-dep'], await testDefaults({saveDev: true}))
  
    const reporter = sinon.spy()
  
    await installPkgs(['dep-of-pkg-with-1-dep@beta'], await testDefaults({saveDev: true, reporter}))
  
    t.ok(reporter.calledWithMatch({
      level: 'info',
      name: 'pnpm:root',
      removed: {
        dependencyType: 'dev',
        name: 'dep-of-pkg-with-1-dep',
        version: '100.0.0',
      },
    } as RootLog), 'reported old version removed from the root')
  
    t.ok(reporter.calledWithMatch({
      added: {
        dependencyType: 'dev',
        name: 'dep-of-pkg-with-1-dep',
        version: '100.1.0',
      },
      level: 'info',
      name: 'pnpm:root',
    } as RootLog), 'reported new version added to the root')
  
    await project.has('dep-of-pkg-with-1-dep')
    await project.storeHas('dep-of-pkg-with-1-dep', '100.1.0')
  
    const pkg = await readPkg()
    t.equal(pkg.devDependencies['dep-of-pkg-with-1-dep'], '^100.1.0')
  })
  
  test('scoped modules with versions (@rstacruz/tap-spec@4.1.1)', async (t) => {
    const project = prepare(t)
    await installPkgs(['@rstacruz/tap-spec@4.1.1'], await testDefaults())
  
    const m = project.requireModule('@rstacruz/tap-spec')
    t.ok(typeof m === 'function', 'tap-spec is available')
  })
  
  test('scoped modules (@rstacruz/tap-spec@*)', async (t) => {
    const project = prepare(t)
    await installPkgs(['@rstacruz/tap-spec@*'], await testDefaults())
  
    const m = project.requireModule('@rstacruz/tap-spec')
    t.ok(typeof m === 'function', 'tap-spec is available')
  })
  
  test('multiple scoped modules (@rstacruz/...)', async (t) => {
    const project = prepare(t)
    await installPkgs(['@rstacruz/tap-spec@*', '@rstacruz/travis-encrypt@*'], await testDefaults())
  
    t.equal(typeof project.requireModule('@rstacruz/tap-spec'), 'function', 'tap-spec is available')
    t.equal(typeof project.requireModule('@rstacruz/travis-encrypt'), 'function', 'travis-encrypt is available')
  })
  
  test('nested scoped modules (test-pnpm-issue219 -> @zkochan/test-pnpm-issue219)', async (t) => {
    const project = prepare(t)
    await installPkgs(['test-pnpm-issue219@1.0.2'], await testDefaults())
  
    const m = project.requireModule('test-pnpm-issue219')
    t.ok(m === 'test-pnpm-issue219,@zkochan/test-pnpm-issue219', 'nested scoped package is available')
  })
  
  test('idempotency (rimraf)', async (t: tape.Test) => {
    const project = prepare(t)
    const reporter = sinon.spy()
    const opts = await testDefaults({reporter})
  
    await installPkgs(['rimraf@2.5.1'], opts)
  
    t.ok(reporter.calledWithMatch({
      added: {
        dependencyType: 'prod',
        name: 'rimraf',
        version: '2.5.1',
      },
      level: 'info',
      name: 'pnpm:root',
    } as RootLog), 'reported that rimraf added to the root')
  
    reporter.reset()
  
    await installPkgs(['rimraf@2.5.1'], opts)
  
    t.notOk(reporter.calledWithMatch({
      added: {
        dependencyType: 'prod',
        name: 'rimraf',
        version: '2.5.1',
      },
      level: 'info',
      name: 'pnpm:root',
    } as RootLog), 'did not reported that rimraf was added because it was already there')
  
    const m = project.requireModule('rimraf')
    t.ok(typeof m === 'function', 'rimraf is available')
  })
  
  test('reporting adding root package', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    await project.storeHas('flatten', '1.0.2')
  
    const reporter = sinon.spy()
  
    await installPkgs(['flatten@1.0.2'], await testDefaults({reporter}))
  
    t.ok(reporter.calledWithMatch({
      added: {
        dependencyType: 'prod',
        name: 'flatten',
        version: '1.0.2',
      },
      level: 'info',
      name: 'pnpm:root',
    } as RootLog), 'reported that flatten added to the root')
  })
  
  test('overwriting (magic-hook@2.0.0 and @0.1.0)', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    await project.storeHas('flatten', '1.0.2')
  
    await installPkgs(['magic-hook@0.1.0'], await testDefaults())
  
    // flatten is not removed from store even though it is unreferenced
    // store should be pruned to have this removed
    await project.storeHas('flatten', '1.0.2')
  
    const m = project.requireModule('magic-hook/package.json')
    t.ok(m.version === '0.1.0', 'magic-hook is 0.1.0')
  })
  
  test('overwriting (is-positive@3.0.0 with is-positive@latest)', async (t) => {
    const project = prepare(t)
    await installPkgs(['is-positive@3.0.0'], await testDefaults({save: true}))
  
    await project.storeHas('is-positive', '3.0.0')
  
    await installPkgs(['is-positive@latest'], await testDefaults({save: true}))
  
    await project.storeHas('is-positive', '3.1.0')
  })
  
  test('forcing', async (t) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPath = path.resolve('node_modules', 'magic-hook', 'dist')
    await rimraf(distPath)
  
    await installPkgs(['magic-hook@2.0.0'], await testDefaults({force: true}))
  
    const distPathExists = await exists(distPath)
    t.ok(distPathExists, 'magic-hook@2.0.0 dist folder reinstalled')
  })
  
  test('argumentless forcing', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPath = path.resolve('node_modules', 'magic-hook', 'dist')
    await rimraf(distPath)
  
    await install(await testDefaults({force: true}))
  
    const distPathExists = await exists(distPath)
    t.ok(distPathExists, 'magic-hook@2.0.0 dist folder reinstalled')
  })
  
  test('no forcing', async (t) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPath = path.resolve('node_modules', 'magic-hook', 'dist')
    await rimraf(distPath)
  
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPathExists = await exists(distPath)
    t.notOk(distPathExists, 'magic-hook@2.0.0 dist folder not reinstalled')
  })
  
  test('refetch package to store if it has been modified', async (t) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPathInStore = await project.resolve('magic-hook', '2.0.0', 'dist')
    await rimraf(distPathInStore)
    await rimraf('node_modules')
    const distPath = path.resolve('node_modules', 'magic-hook', 'dist')
  
    await installPkgs(['magic-hook@2.0.0'], await testDefaults())
  
    const distPathExists = await exists(distPath)
    t.ok(distPathExists, 'magic-hook@2.0.0 dist folder reinstalled')
  })
  
  test("don't refetch package to store if it has been modified and verify-store-integrity = false", async (t: tape.Test) => {
    const project = prepare(t)
    const opts = await testDefaults({verifyStoreIntegrity: false})
    await installPkgs(['magic-hook@2.0.0'], opts)
  
    await writeJsonFile(path.join(await project.getStorePath(), 'localhost+4873', 'magic-hook', '2.0.0', 'node_modules', 'magic-hook', 'package.json'), {})
  
    await rimraf('node_modules')
  
    await installPkgs(['magic-hook@2.0.0'], opts)
  
    t.deepEqual(project.requireModule('magic-hook/package.json'), {}, 'package.json not refetched even though it was mutated')
  })
  
  // TODO: decide what to do with this case
  test.skip('relink package to project if the dependency is not linked from store', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['magic-hook@2.0.0'], await testDefaults({save: true, saveExact: true}))
  
    const pkgJsonPath = path.resolve('node_modules', 'magic-hook', 'package.json')
  
    async function getInode () {
      return (await fs.stat(pkgJsonPath)).ino
    }
  
    const storeInode = await getInode()
  
    // rewriting package.json, to destroy the link
    const pkgJson = await fs.readFile(pkgJsonPath, 'utf8')
    await rimraf(pkgJsonPath)
    await fs.writeFile(pkgJsonPath, pkgJson, 'utf8')
  
    t.ok(storeInode !== await getInode(), 'package.json inode changed')
  
    await install(await testDefaults({repeatInstallDepth: 0}))
  
    t.ok(storeInode === await getInode(), 'package.json inode matches the one that is in store')
  })
  
  test('circular deps', async (t: tape.Test) => {
    const project = prepare(t)
    await installPkgs(['circular-deps-1-of-2'], await testDefaults())
  
    const m = project.requireModule('circular-deps-1-of-2/mirror')
  
    t.equal(m(), 'circular-deps-1-of-2', 'circular dependencies can access each other')
  
    t.notOk(await exists(path.join('node_modules', 'circular-deps-1-of-2', 'node_modules', 'circular-deps-2-of-2', 'node_modules', 'circular-deps-1-of-2')), 'circular dependency is avoided')
  })
  
  test('concurrent circular deps', async (t: tape.Test) => {
    // es5-ext is an external package from the registry
    // the latest dist-tag is overriden to have a stable test
    await addDistTag('es5-ext', '0.10.31', 'latest')
    await addDistTag('es6-iterator', '2.0.1', 'latest')
  
    const project = prepare(t)
    await installPkgs(['es6-iterator@2.0.0'], await testDefaults())
  
    const m = project.requireModule('es6-iterator')
  
    t.ok(m, 'es6-iterator is installed')
    t.ok(await exists(path.join('node_modules', '.localhost+4873', 'es6-iterator', '2.0.0', 'node_modules', 'es5-ext')))
    t.ok(await exists(path.join('node_modules', '.localhost+4873', 'es6-iterator', '2.0.1', 'node_modules', 'es5-ext')))
    t.ok(await exists(path.join('node_modules', '.localhost+4873', 'es5-ext', '0.10.31', 'node_modules', 'es6-iterator')))
    t.ok(await exists(path.join('node_modules', '.localhost+4873', 'es5-ext', '0.10.31', 'node_modules', 'es6-symbol')))
  })
  
  test('concurrent installation of the same packages', async (t) => {
    const project = prepare(t)
  
    // the same version of core-js is required by two different dependencies
    // of babek-core
    await installPkgs(['babel-core@6.21.0'], await testDefaults())
  
    const m = project.requireModule('babel-core')
  
    t.ok(m, 'babel-core is installed')
  })
  
  test('big with dependencies and circular deps (babel-preset-2015)', async (t) => {
    const project = prepare(t)
    await installPkgs(['babel-preset-es2015@6.3.13'], await testDefaults())
  
    const m = project.requireModule('babel-preset-es2015')
    t.ok(typeof m === 'object', 'babel-preset-es2015 is available')
  })
  
  test('bundledDependencies (pkg-with-bundled-dependencies@1.0.0)', async (t: tape.Test) => {
    const project = prepare(t)
  
    await installPkgs(['pkg-with-bundled-dependencies@1.0.0'], await testDefaults())
  
    await project.isExecutable('pkg-with-bundled-dependencies/node_modules/.bin/hello-world-js-bin')
  
    const shr = await project.loadShrinkwrap()
    t.deepEqual(
      shr.packages['/pkg-with-bundled-dependencies/1.0.0'].bundledDependencies,
      ['hello-world-js-bin'],
      'bundledDependencies added to shrinkwrap.yaml',
    )
  })
  
  test('bundleDependencies (pkg-with-bundle-dependencies@1.0.0)', async (t: tape.Test) => {
    const project = prepare(t)
  
    await installPkgs(['pkg-with-bundle-dependencies@1.0.0'], await testDefaults())
  
    await project.isExecutable('pkg-with-bundle-dependencies/node_modules/.bin/hello-world-js-bin')
  
    const shr = await project.loadShrinkwrap()
    t.deepEqual(
      shr.packages['/pkg-with-bundle-dependencies/1.0.0'].bundledDependencies,
      ['hello-world-js-bin'],
      'bundledDependencies added to shrinkwrap.yaml',
    )
  })
  
  test('compiled modules (ursa@0.9.1)', async (t) => {
    // TODO: fix this for Node.js v7
    if (!isCI || IS_WINDOWS || semver.satisfies(process.version, '>=7.0.0')) {
      t.skip('runs only on CI')
      return
    }
  
    const project = prepare(t)
    await installPkgs(['ursa@0.9.1'], await testDefaults())
  
    const m = project.requireModule('ursa')
    t.ok(typeof m === 'object', 'ursa() is available')
  })
  
  test('shrinkwrap compatibility', async (t) => {
    if (semver.satisfies(process.version, '4')) {
      t.skip("don't run on Node.js 4")
      return
    }
    const project = prepare(t, { dependencies: { rimraf: '*' } })
  
    await installPkgs(['rimraf@2.5.1'], await testDefaults())
  
    return new Promise((resolve, reject) => {
      const proc = crossSpawn.spawn('npm', ['shrinkwrap'])
  
      proc.on('error', reject)
  
      proc.on('close', (code: number) => {
        if (code > 0) return reject(new Error('Exit code ' + code))
        const wrap = JSON.parse(fs.readFileSync('npm-shrinkwrap.json', 'utf-8'))
        t.ok(wrap.dependencies.rimraf.version === '2.5.1',
          'npm shrinkwrap is successful')
        resolve()
      })
    })
  })
  
  const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
  
  test('support installing into the same store simultaneously', async (t) => {
    const project = prepare(t)
    await Promise.all([
      installPkgs(['pkg-that-installs-slowly'], await testDefaults()),
      wait(500) // to be sure that lock was created
        .then(async () => {
          await project.storeHasNot('pkg-that-installs-slowly')
          await installPkgs(['rimraf@2.5.1'], await testDefaults())
        })
        .then(async  () => {
          await project.has('pkg-that-installs-slowly')
          await project.has('rimraf')
        })
        .catch((err) => t.notOk(err)),
    ])
  })
  
  test('support installing and uninstalling from the same store simultaneously', async (t) => {
    const project = prepare(t)
    await Promise.all([
      installPkgs(['pkg-that-installs-slowly'], await testDefaults()),
      wait(500) // to be sure that lock was created
        .then(async () => {
          await project.storeHasNot('pkg-that-installs-slowly')
          await uninstall(['rimraf@2.5.1'], await testDefaults())
        })
        .then(async () => {
          await project.has('pkg-that-installs-slowly')
          await project.hasNot('rimraf')
        })
        .catch((err) => t.notOk(err)),
    ])
  })
  
  test('top-level packages should find the plugins they use', async (t) => {
    const project = prepare(t, {
      scripts: {
        test: 'pkg-that-uses-plugins',
      },
    })
    await installPkgs(['pkg-that-uses-plugins', 'plugin-example'], await testDefaults({ save: true }))
    const result = spawnSync('npm', ['test'])
    t.ok(result.stdout.toString().indexOf('My plugin is plugin-example') !== -1, 'package executable have found its plugin')
    t.equal(result.status, 0, 'executable exited with success')
  })
  
  test('not top-level packages should find the plugins they use', async (t: tape.Test) => {
    // standard depends on eslint and eslint plugins
    const project = prepare(t, {
      scripts: {
        test: 'standard',
      },
    })
    await installPkgs(['standard@8.6.0'], await testDefaults({ save: true }))
    const result = spawnSync('npm', ['test'])
    t.equal(result.status, 0, 'standard exited with success')
  })
  
  test('bin specified in the directories property linked to .bin folder', async (t) => {
    const project = prepare(t)
  
    await installPkgs(['pkg-with-directories-bin'], await testDefaults())
  
    await project.isExecutable('.bin/pkg-with-directories-bin')
  })
  
  test('run js bin file', async (t) => {
    const project = prepare(t, {
      scripts: {
        test: 'hello-world-js-bin',
      },
    })
    await installPkgs(['hello-world-js-bin'], await testDefaults({ save: true }))
  
    const result = spawnSync('npm', ['test'])
    t.ok(result.stdout.toString().indexOf('Hello world!') !== -1, 'package executable printed its message')
    t.equal(result.status, 0, 'executable exited with success')
  })
  
  test('building native addons', async (t) => {
    const project = prepare(t)
  
    await installPkgs(['runas@3.1.1'], await testDefaults())
  
    t.ok(await exists(path.join('node_modules', 'runas', 'build')), 'build folder created')
  })
  
  test('should update subdep on second install', async (t: tape.Test) => {
    const project = prepare(t)
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', 'latest')
  
    await installPkgs(['pkg-with-1-dep'], await testDefaults({save: true}))
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  
    let shr = await project.loadShrinkwrap()
  
    t.ok(shr.packages['/dep-of-pkg-with-1-dep/100.0.0'], 'shrinkwrap has resolution for package')
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
  
    const reporter = sinon.spy()
  
    await install(await testDefaults({depth: 1, update: true, reporter}))
  
    t.ok(reporter.calledWithMatch({
      added: 1,
      level: 'debug',
      name: 'pnpm:stats',
    } as StatsLog), 'added stat')
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.1.0')
  
    shr = await project.loadShrinkwrap()
  
    t.notOk(shr.packages['/dep-of-pkg-with-1-dep/100.0.0'], "shrinkwrap doesn't have old dependency")
    t.ok(shr.packages['/dep-of-pkg-with-1-dep/100.1.0'], 'shrinkwrap has new dependency')
  
    t.equal(deepRequireCwd(['pkg-with-1-dep', 'dep-of-pkg-with-1-dep', './package.json']).version, '100.1.0', 'updated in node_modules')
  })
  
  test('should not update subdep when depth is smaller than depth of package', async (t: tape.Test) => {
    const project = prepare(t)
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', 'latest')
  
    await installPkgs(['pkg-with-1-dep'], await testDefaults({save: true}))
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  
    let shr = await project.loadShrinkwrap()
  
    t.ok(shr.packages['/dep-of-pkg-with-1-dep/100.0.0'], 'shrinkwrap has resolution for package')
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
  
    await install(await testDefaults({depth: 0, update: true}))
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  
    shr = await project.loadShrinkwrap()
  
    t.ok(shr.packages['/dep-of-pkg-with-1-dep/100.0.0'], 'shrinkwrap has old dependency')
    t.notOk(shr.packages['/dep-of-pkg-with-1-dep/100.1.0'], 'shrinkwrap has not the new dependency')
  
    t.equal(deepRequireCwd(['pkg-with-1-dep', 'dep-of-pkg-with-1-dep', './package.json']).version, '100.0.0', 'not updated in node_modules')
  })
  
  test('should install dependency in second project', async (t) => {
    const project1 = prepare(t)
  
    await installPkgs(['pkg-with-1-dep'], await testDefaults({save: true, store: '../store'}))
    t.equal(project1.requireModule('pkg-with-1-dep')().name, 'dep-of-pkg-with-1-dep', 'can require in 1st pkg')
  
    const project2 = prepare(t)
  
    await installPkgs(['pkg-with-1-dep'], await testDefaults({save: true, store: '../store'}))
  
    t.equal(project2.requireModule('pkg-with-1-dep')().name, 'dep-of-pkg-with-1-dep', 'can require in 2nd pkg')
  })
  
  test('should throw error when trying to install using a different store then the previous one', async (t) => {
    const project = prepare(t)
  
    await installPkgs(['rimraf@2.5.1'], await testDefaults({store: 'node_modules/.store1'}))
  
    try {
      await installPkgs(['is-negative'], await testDefaults({store: 'node_modules/.store2'}))
      t.fail('installation should have failed')
    } catch (err) {
      t.equal(err.code, 'UNEXPECTED_STORE', 'failed with correct error code')
    }
  })
  
  test('ignores drive case in store path', async (t: tape.Test) => {
    if (!isWindows()) return
  
    const project = prepare(t)
  
    // paths are case-insensitive on windows, so we will test with an upper and lower-case store
    const storePathUpper: string = path.resolve('node_modules/.store1').toUpperCase();
    const storePathLower: string = storePathUpper.toLowerCase();
  
    await installPkgs(['rimraf@2.5.1'], await testDefaults({store: storePathUpper}))
    await installPkgs(['is-negative'], await testDefaults({store: storePathLower}))
    t.pass('Install did not fail')
  })
  
  test('should not throw error if using a different store after all the packages were uninstalled', async (t) => {
    // TODO: implement
  })
  
  test('shrinkwrap locks npm dependencies', async (t: tape.Test) => {
    const project = prepare(t)
    const reporter = sinon.spy()
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.0.0', 'latest')
  
    await installPkgs(['pkg-with-1-dep'], await testDefaults({save: true, reporter}))
  
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      name: 'pnpm:progress',
      pkgId: 'localhost+4873/pkg-with-1-dep/100.0.0',
      status: 'resolving_content',
    } as ProgressLog), 'logs that package is being resolved')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      pkgId: 'localhost+4873/pkg-with-1-dep/100.0.0',
      status: 'fetched',
    } as ProgressLog), 'logged that package was fetched from registry')
  
    await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
  
    await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
  
    await rimraf('node_modules')
  
    reporter.reset()
    await install(await testDefaults({reporter}))
  
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      pkgId: 'localhost+4873/pkg-with-1-dep/100.0.0',
      status: 'resolving_content',
    } as ProgressLog), 'logs that package is being resolved')
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      pkgId: 'localhost+4873/pkg-with-1-dep/100.0.0',
      status: 'found_in_store',
    } as ProgressLog), 'logged that package was found in store')
  
    const m = project.requireModule('.localhost+4873/pkg-with-1-dep/100.0.0/node_modules/dep-of-pkg-with-1-dep/package.json')
  
    t.equal(m.version, '100.0.0', 'dependency specified in shrinkwrap.yaml is installed')
  })
  
  test('self-require should work', async (t) => {
    const project = prepare(t)
  
    await installPkgs(['uses-pkg-with-self-usage'], await testDefaults())
  
    t.ok(project.requireModule('uses-pkg-with-self-usage'))
  })
  
  test('install on project with lockfile and no node_modules', async (t: tape.Test) => {
    const project = prepare(t)
  
    await installPkgs(['is-negative'], await testDefaults())
  
    await rimraf('node_modules')
  
    await installPkgs(['is-positive'], await testDefaults())
  
    t.ok(project.requireModule('is-positive'), 'installed new dependency')
  
    await project.hasNot('is-negative')
  })
  
  test('install a dependency with * range', async (t: tape.Test) => {
    const project = prepare(t, {
      dependencies: {
        'has-beta-only': '*',
      },
    })
    const reporter = sinon.spy()
  
    await install(await testDefaults({reporter}))
  
    await project.has('has-beta-only')
  
    t.ok(reporter.calledWithMatch({
      level: 'debug',
      name: 'pnpm:package-json',
      updated: {
        dependencies: {
          'has-beta-only': '*',
        },
        name: 'project',
        version: '0.0.0',
      },
    } as PackageJsonLog), 'should log package-json updated even when package.json was not changed')
  })
  
  test('create a package.json if there is none', async (t: tape.Test) => {
    const project = prepare(t)
    await rimraf('package.json')
  
    await installPkgs(['dep-of-pkg-with-1-dep@100.1.0'], await testDefaults())
  
    t.deepEqual(await readPkg({normalize: false}), {
      dependencies: {
        'dep-of-pkg-with-1-dep': '^100.1.0',
      },
    }, 'package.json created')
  })
  