Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRebecca Turner <me@re-becca.org>2017-04-07 01:24:31 +0300
committerRebecca Turner <me@re-becca.org>2017-05-26 04:55:03 +0300
commitc0a30c0725070dc49ac9e004f9e33bac68c69e20 (patch)
treeedeb150fec2c8a318086c8ec18aff544655baf5e /test
parentd61b65d26d054c24af37366461e0275073e7739f (diff)
test: Spec tests for local specifiers
Diffstat (limited to 'test')
-rw-r--r--test/tap/spec-local-specifiers.js629
1 files changed, 629 insertions, 0 deletions
diff --git a/test/tap/spec-local-specifiers.js b/test/tap/spec-local-specifiers.js
new file mode 100644
index 000000000..608d5503a
--- /dev/null
+++ b/test/tap/spec-local-specifiers.js
@@ -0,0 +1,629 @@
+'use strict'
+var path = require('path')
+var test = require('tap').test
+var fs = require('fs')
+var rimraf = require('rimraf')
+var mr = require('npm-registry-mock')
+var Tacks = require('tacks')
+var File = Tacks.File
+var Symlink = Tacks.Symlink
+var Dir = Tacks.Dir
+var common = require('../common-tap.js')
+var isWindows = require('../../lib/utils/is-windows.js')
+
+var basedir = path.join(__dirname, path.basename(__filename, '.js'))
+var testdir = path.join(basedir, 'testdir')
+var cachedir = path.join(basedir, 'cache')
+var globaldir = path.join(basedir, 'global')
+var tmpdir = path.join(basedir, 'tmp')
+
+var conf = {
+ cwd: testdir,
+ env: common.newEnv().extend({
+ npm_config_cache: cachedir,
+ npm_config_tmp: tmpdir,
+ npm_config_prefix: globaldir,
+ npm_config_registry: common.registry,
+ npm_config_loglevel: 'error'
+ }),
+ stdio: [0, 'pipe', 2]
+}
+var confE = {
+ cwd: testdir,
+ env: conf.env,
+ stdio: [0, 'pipe', 'pipe']
+}
+
+function readJson (file) {
+ return JSON.parse(fs.readFileSync(file))
+}
+
+function isSymlink (t, file, message) {
+ try {
+ var info = fs.lstatSync(file)
+ t.is(info.isSymbolicLink(), true, message)
+ } catch (ex) {
+ if (ex.code === 'ENOENT') {
+ t.fail(message, {found: null, wanted: 'symlink', compare: 'fs.lstat(' + file + ')'})
+ } else {
+ t.fail(message, {found: ex, wanted: 'symlink', compare: 'fs.lstat(' + file + ')'})
+ }
+ }
+}
+
+function fileExists (t, file, message) {
+ try {
+ fs.statSync(file)
+ t.pass(message)
+ } catch (ex) {
+ if (ex.code === 'ENOENT') {
+ t.fail(message, {found: null, wanted: 'exists', compare: 'fs.stat(' + file + ')'})
+ } else {
+ t.fail(message, {found: ex, wanted: 'exists', compare: 'fs.stat(' + file + ')'})
+ }
+ }
+}
+
+function noFileExists (t, file, message) {
+ try {
+ fs.statSync(file)
+ t.fail(message, {found: 'exists', wanted: 'not exists', compare: 'fs.stat(' + file + ')'})
+ } catch (ex) {
+ if (ex.code === 'ENOENT') {
+ t.pass(message)
+ } else {
+ t.fail(message, {found: ex, wanted: 'not exists', compare: 'fs.stat(' + file + ')'})
+ }
+ }
+}
+
+var server
+var testdirContent = {
+ node_modules: Dir({}),
+ pkga: Dir({
+ 'package.json': File({
+ name: 'pkga',
+ version: '1.0.0'
+ })
+ }),
+ pkgb: Dir({
+ 'package.json': File({
+ name: 'pkgb',
+ version: '1.0.0'
+ })
+ }),
+ pkgc: Dir({
+ 'package.json': File({
+ name: 'pkgc',
+ version: '1.0.0'
+ })
+ }),
+ pkgd: Dir({
+ 'package.json': File({
+ name: 'pkgd',
+ version: '1.0.0'
+ })
+ })
+}
+
+var fixture
+function setup () {
+ fixture = new Tacks(Dir({
+ cache: Dir(),
+ global: Dir(),
+ tmp: Dir(),
+ testdir: Dir(testdirContent)
+ }))
+ cleanup()
+ fixture.create(basedir)
+}
+
+function cleanup () {
+ fixture.remove(basedir)
+}
+
+test('setup', function (t) {
+ process.nextTick(function () {
+ setup()
+ mr({port: common.port, throwOnUnmatched: true}, function (err, s) {
+ if (err) throw err
+ server = s
+ t.done()
+ })
+ })
+})
+
+var installOk = []
+var slashes = [ 'unix', 'win' ]
+slashes.forEach(function (os) {
+ var slash = os === 'unix'
+ ? function (ss) { return ss.replace(/\\/g, '/') }
+ : function (ss) { return ss.replace(/\//g, '\\') }
+ installOk.push(os + '-file-abs-f')
+ testdirContent[os + '-file-abs-f'] = Dir({
+ 'package.json': File({
+ name: os + '-file-abs-f',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file:' + slash(testdir + '/pkga')
+ }
+ })
+ })
+ installOk.push(os + '-file-abs-fff')
+ testdirContent[os + '-file-abs-fff'] = Dir({
+ 'package.json': File({
+ name: os + '-file-abs-fff',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file://' + slash(testdir + '/pkga')
+ }
+ })
+ })
+ installOk.push(os + '-file-rel')
+ testdirContent[os + '-file-rel'] = Dir({
+ 'package.json': File({
+ name: os + '-file-rel',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file:' + slash('../pkga')
+ }
+ })
+ })
+ installOk.push(os + '-file-rel-fffff')
+ testdirContent[os + '-file-rel-fffff'] = Dir({
+ 'package.json': File({
+ name: os + '-file-rel-fffff',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file:' + slash('/////../pkga')
+ }
+ })
+ })
+})
+
+testdirContent['win-abs-drive-win'] = Dir({
+ 'package.json': File({
+ name: 'win-abs-drive-win',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file:D:\\thing\\pkga'
+ }
+ })
+})
+
+testdirContent['win-abs-drive-unix'] = Dir({
+ 'package.json': File({
+ name: 'win-abs-drive-unix',
+ version: '1.0.0',
+ dependencies: {
+ pkga: 'file://D:/thing/pkga'
+ }
+ })
+})
+
+test('specifiers', function (t) {
+ t.plan(installOk.length + 2)
+ installOk.forEach(function (mod) {
+ t.test(mod, function (t) {
+ common.npm(['install', '--dry-run', '--json', 'file:' + mod], conf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ t.comment(stdout.trim())
+ t.done()
+ })
+ })
+ })
+ slashes.forEach(function (os) {
+ t.test('win-abs-drive-' + os, function (t) {
+ common.npm(['install', '--dry-run', '--json', 'file:win-abs-drive-' + os], confE, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.not(code, 0, 'command errored ok')
+ t.comment(stderr.trim())
+ if (isWindows) {
+ t.test('verify failure of file-not-found or wrong drive letter on windows')
+ } else {
+ var result = JSON.parse(stdout)
+ t.is(result.error && result.error.code, 'EWINDOWSPATH', 'verify failure due to windows paths not supported on non-Windows')
+ }
+
+ t.done()
+ })
+ })
+ })
+})
+testdirContent['mkdirp'] = Dir({
+ 'package.json': File({
+ name: 'mkdirp',
+ version: '9.9.9'
+ })
+})
+testdirContent['example'] = Dir({
+ 'minimist': Dir({
+ 'package.json': File({
+ name: 'minimist',
+ version: '9.9.9'
+ })
+ })
+})
+testdirContent['wordwrap'] = Dir({
+})
+testdirContent['prefer-pkg'] = Dir({
+ 'package.json': File({
+ name: 'perfer-pkg',
+ version: '1.0.0',
+ dependencies: {
+ 'mkdirp': 'latest'
+ }
+ }),
+ 'latest': Dir({
+ 'package.json': File({
+ name: 'mkdirp',
+ version: '9.9.9'
+ })
+ })
+})
+
+test('ambiguity', function (t) {
+ t.plan(5)
+ t.test('arg: looks like package name, is dir', function (t) {
+ common.npm(['install', 'mkdirp', '--dry-run', '--json'], conf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ const result = JSON.parse(stdout.trim())
+ t.like(result, {added: [{name: 'mkdirp', version: '9.9.9'}]}, 'got local dir')
+ t.done()
+ })
+ })
+ t.test('arg: looks like package name, is package', function (t) {
+ common.npm(['install', 'wordwrap', '--dry-run', '--json'], conf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ const result = JSON.parse(stdout.trim())
+ t.like(result, {added: [{name: 'wordwrap', version: '0.0.2'}]}, 'even with local dir w/o package.json, got global')
+ t.done()
+ })
+ })
+ t.test('arg: looks like github repo, is dir', function (t) {
+ common.npm(['install', 'example/minimist', '--dry-run', '--json'], conf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ const result = JSON.parse(stdout.trim())
+ t.like(result, {added: [{name: 'minimist', version: '9.9.9'}]}, 'got local dir')
+ t.done()
+ })
+ })
+ t.test('package: looks like tag, has dir, use tag', function (t) {
+ common.npm(['install', '--dry-run', '--json'], {cwd: path.join(testdir, 'prefer-pkg'), env: conf.env}, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ const result = JSON.parse(stdout.trim())
+ t.like(result, {added: [{name: 'mkdirp', version: '0.3.5'}]}, 'got local dir')
+ t.done()
+ })
+ })
+
+ t.test('test ambiguity for github repos')
+})
+testdirContent['existing-matches'] = Dir({
+ 'package.json': File({
+ name: 'existing-matches',
+ version: '1.0.0',
+ dependencies: {
+ 'pkga': 'file:../pkga',
+ 'pkgb': 'file:' + testdir + '/pkgb',
+ 'pkgc': 'file:../pkgc',
+ 'pkgd': 'file:' + testdir + '/pkgd'
+ }
+ }),
+ 'node_modules': Dir({
+ 'pkga': Symlink('../../pkga'),
+ 'pkgd': Symlink('../../pkgd')
+ })
+})
+
+test('existing install matches', function (t) {
+ t.plan(1)
+ // have to make these by hand because tacks doesn't support absolute paths in symlinks
+ fs.symlinkSync(testdir + '/pkgb', testdir + '/existing-matches/node_modules/pkgb', 'junction')
+ fs.symlinkSync(testdir + '/pkgc', testdir + '/existing-matches/node_modules/pkgc', 'junction')
+ t.test('relative symlink counts as match of relative symlink in package.json', function (t) {
+ common.npm(['ls', '--json'], {cwd: path.join(testdir, 'existing-matches'), env: conf.env}, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ if (stdout) t.comment(stdout.trim())
+ t.test('specifically test that output is valid')
+ // relative symlink counts as match of relative symlink in package.json (pkga)
+ // relative symlink counts as match of abs symlink in package.json (pkgc)
+ // abs symlink counts as match of relative symlink in package.json (pkgb)
+ // abs symlink counts as match of abs symlink in package.json (pkgd)
+ t.done()
+ })
+ })
+})
+var ibdir = testdir + '/install-behavior'
+testdirContent['ib-out'] = Dir({
+ 'package.json': File({
+ name: 'ib-out',
+ version: '1.0.0',
+ dependencies: {
+ 'minimist': '*'
+ }
+ })
+})
+
+testdirContent['install-behavior'] = Dir({
+ 'package.json': File({
+ name: 'install-behavior',
+ version: '1.0.0'
+ }),
+ 'ib-in': Dir({
+ 'package.json': File({
+ name: 'ib-in',
+ version: '1.0.0',
+ dependencies: {
+ 'mkdirp': '*'
+ }
+ })
+ }),
+ 'noext': File(new Buffer(
+ '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' +
+ '06066626260a20dadccc144c1b1841f86000923334363037343536343732' +
+ '633000728c0c80f2d4760836505a5c925804740aa5e640bca200a78708a8' +
+ '56ca4bcc4d55b252cacb4fad2851d251502a4b2d2acecccf030a19ea19e8' +
+ '1928d5720db41b47c1281805a36014501f00005012007200080000',
+ 'hex'
+ )),
+ 'tarball-1.0.0.tgz': File(new Buffer(
+ '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' +
+ '06066626260a20dadccc144c1b1841f8606062a6c060686c606e686a6c68' +
+ '666ec26000e480e5a9ed106ca0b4b824b108e8144acd817845014e0f1150' +
+ 'ad9497989baa64a5040c85a4c49c1c251d05a5b2d4a2e2ccfc3ca0a0a19e' +
+ '819e81522dd740bb72148c8251300a4601b50100473dd15800080000',
+ 'hex'
+ )),
+ 'not-module': Dir({}),
+ 'test-preinstall': Dir({
+ 'package.json': File({
+ name: 'test-preinstall',
+ version: '1.0.0',
+ scripts: {
+ 'preinstall': 'node -p "\'CWD:\' + process.cwd()"'
+ }
+ })
+ })
+})
+
+test('install behavior', function (t) {
+ var ibconf = {cwd: ibdir, env: conf.env.extend({npm_config_loglevel: 'silent'}), stdio: conf.stdio}
+ t.plan(7)
+ t.test('transitive deps for in-larger-module cases', function (t) {
+ common.npm(['install', 'file:ib-in'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ if (stdout) t.comment(stdout.trim())
+ fileExists(t, ibdir + '/node_modules/mkdirp', 'transitive dep flattened')
+ isSymlink(t, ibdir + '/node_modules/ib-in', 'dep is symlink')
+ noFileExists(t, ibdir + '/ib-in/node_modules/mkdirp', 'transitive dep not nested')
+ t.done()
+ })
+ })
+ t.test('transitive deps for out-of-larger module cases', function (t) {
+ common.npm(['install', 'file:../ib-out'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ if (stdout) t.comment(stdout.trim())
+ noFileExists(t, ibdir + '/node_modules/minimist', 'transitive dep not flattened')
+ fileExists(t, testdir + '/ib-out/node_modules/minimist', 'transitive dep nested')
+ t.done()
+ })
+ })
+ t.test('transitive deps for out-of-larger module cases w/ --preserve-symlinks', function (t) {
+ rimraf.sync(ibdir + '/node_modules')
+ rimraf.sync(testdir + '/ib-out/node_modules')
+ var env = conf.env.extend({NODE_PRESERVE_SYMLINKS: '1'})
+ common.npm(['install', 'file:../ib-out'], {cwd: ibdir, env: env}, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ if (stdout) t.comment(stdout.trim())
+ fileExists(t, ibdir + '/node_modules/minimist', 'transitive dep flattened')
+ noFileExists(t, testdir + '/ib-out/node_modules/minimist', 'transitive dep not nested')
+ t.done()
+ })
+ })
+ t.test('tar/tgz/tar.gz should install a tarball', function (t) {
+ common.npm(['install', 'file:tarball-1.0.0.tgz'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ if (stdout) t.comment(stdout.trim())
+ fileExists(t, ibdir + '/node_modules/tarball')
+ t.done()
+ })
+ })
+ t.test('non tar/tgz/tar.gz files should give good error message', function (t) {
+ common.npm(['install', 'file:noext', '--json'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.not(code, 0, 'do not install files w/o extensions')
+ noFileExists(t, ibdir + '/node_modules/noext')
+ var result = JSON.parse(stdout)
+ t.like(result, {error: {code: 'ENOLOCAL'}}, 'new type of error')
+ t.done()
+ })
+ })
+ t.test('directories without package.json should give good error message', function (t) {
+ common.npm(['install', 'file:not-module', '--json'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.not(code, 0, 'error on dir w/o module')
+ var result = JSON.parse(stdout)
+ t.like(result, {error: {code: 'ENOLOCAL'}}, 'new type of error')
+ t.done()
+ })
+ })
+ t.test('verify preinstall step runs after finalize, such that cwd is as expected', function (t) {
+ common.npm(['install', 'file:test-preinstall'], ibconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ isSymlink(t, `${ibdir}/node_modules/test-preinstall`, 'installed as symlink')
+ t.notLike(stdout, /CWD:.*[.]staging/, 'cwd should not be in staging')
+
+ t.test('verify that env is as expected')
+ t.done()
+ })
+ })
+})
+var sbdir = testdir + '/save-behavior'
+testdirContent['save-behavior'] = Dir({
+ 'package.json': File({
+ name: 'save-behavior',
+ version: '1.0.0'
+ }),
+ 'npm-shrinkwrap.json': File({
+ name: 'save-behavior',
+ version: '1.0.0',
+ dependencies: {}
+ }),
+ 'transitive': Dir({
+ 'package.json': File({
+ name: 'transitive',
+ version: '1.0.0',
+ dependencies: {
+ 'pkgc': 'file:../../pkgc'
+ }
+ })
+ })
+})
+testdirContent['sb-transitive'] = Dir({
+ 'package.json': File({
+ name: 'sb-transitive',
+ version: '1.0.0',
+ dependencies: {
+ 'sbta': 'file:sbta'
+ }
+ }),
+ 'sbta': Dir({
+ 'package.json': File({
+ name: 'sbta',
+ version: '1.0.0'
+ })
+ })
+})
+var sbdirp = testdir + '/save-behavior-pre'
+testdirContent['save-behavior-pre'] = Dir({
+ 'package.json': File({
+ name: 'save-behavior',
+ version: '1.0.0'
+ }),
+ 'npm-shrinkwrap.json': File({
+ name: 'save-behavior',
+ version: '1.0.0',
+ dependencies: {}
+ })
+})
+testdirContent['sb-transitive-preserve'] = Dir({
+ 'package.json': File({
+ name: 'sb-transitive-preserve',
+ version: '1.0.0',
+ dependencies: {
+ 'sbtb': 'file:sbtb'
+ }
+ }),
+ 'sbtb': Dir({
+ 'package.json': File({
+ name: 'sbtb',
+ version: '1.0.0'
+ })
+ })
+})
+test('save behavior', function (t) {
+ t.plan(6)
+ var sbconf = {cwd: sbdir, env: conf.env, stdio: conf.stdio}
+ t.test('to package.json and npm-shrinkwrap.json w/ abs', function (t) {
+ common.npm(['install', '--save', 'file:' + testdir + '/pkga'], sbconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ var pjson = readJson(sbdir + '/package.json')
+ var shrinkwrap = readJson(sbdir + '/npm-shrinkwrap.json')
+ t.is(pjson.dependencies.pkga, 'file:../pkga', 'package.json')
+ var sdep = shrinkwrap.dependencies
+ t.like(sdep, {pkga: {version: 'file:../pkga', resolved: null}}, 'npm-shrinkwrap.json')
+ t.done()
+ })
+ })
+ t.test('to package.json and npm-shrinkwrap.json w/ drive abs')
+ t.test('to package.json and npm-shrinkwrap.json w/ rel', function (t) {
+ common.npm(['install', '--save', 'file:../pkgb'], sbconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ var pjson = readJson(sbdir + '/package.json')
+ var shrinkwrap = readJson(sbdir + '/npm-shrinkwrap.json')
+ t.is(pjson.dependencies.pkgb, 'file:../pkgb', 'package.json')
+ var sdep = shrinkwrap.dependencies
+ t.like(sdep, {pkgb: {version: 'file:../pkgb', resolved: null}}, 'npm-shrinkwrap.json')
+ t.done()
+ })
+ })
+ t.test('internal transitive dependencies of shrinkwraps', function (t) {
+ common.npm(['install', '--save', 'file:transitive'], sbconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ var pjson = readJson(sbdir + '/package.json')
+ var shrinkwrap = readJson(sbdir + '/npm-shrinkwrap.json')
+ t.is(pjson.dependencies.transitive, 'file:transitive', 'package.json')
+ var sdep = shrinkwrap.dependencies.transitive || {}
+ var tdep = shrinkwrap.dependencies.pkgc
+ t.is(sdep.version, 'file:transitive', 'npm-shrinkwrap.json direct dep')
+ t.is(tdep.version, 'file:../pkgc', 'npm-shrinkwrap.json transitive dep')
+ t.done()
+ })
+ })
+ t.test('external transitive dependencies of shrinkwraps', function (t) {
+ common.npm(['install', '--save', 'file:../sb-transitive'], sbconf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ var pjson = readJson(sbdir + '/package.json')
+ var shrinkwrap = readJson(sbdir + '/npm-shrinkwrap.json')
+ var deps = pjson.dependencies || {}
+ t.is(deps['sb-transitive'], 'file:../sb-transitive', 'package.json')
+ var sdep = shrinkwrap.dependencies['sb-transitive'] || {}
+ var tdep = sdep.dependencies.sbta
+ t.like(tdep, {bundled: true, version: 'file:../sb-transitive/sbta'}, 'npm-shrinkwrap.json transitive dep')
+ t.like(sdep, {bundled: null, version: 'file:../sb-transitive'}, 'npm-shrinkwrap.json direct dep')
+ t.done()
+ })
+ })
+ t.test('external transitive dependencies of shrinkwraps > preserve symlinks', function (t) {
+ var preserveEnv = conf.env.extend({NODE_PRESERVE_SYMLINKS: '1'})
+ var preserveConf = {cwd: sbdirp, env: preserveEnv, stdio: conf.stdio}
+ common.npm(['install', '--save', 'file:../sb-transitive-preserve'], preserveConf, function (err, code, stdout) {
+ if (err) throw err
+ t.is(code, 0, 'command ran ok')
+ var pjson = readJson(sbdirp + '/package.json')
+ var shrinkwrap = readJson(sbdirp + '/npm-shrinkwrap.json')
+ t.is(pjson.dependencies['sb-transitive-preserve'], 'file:../sb-transitive-preserve', 'package.json')
+ var sdep = shrinkwrap.dependencies['sb-transitive-preserve'] || {}
+ var tdep = shrinkwrap.dependencies.sbtb
+ t.like(sdep, {bundled: null, version: 'file:../sb-transitive-preserve'}, 'npm-shrinkwrap.json direct dep')
+ t.like(tdep, {bundled: null, version: 'file:../sb-transitive-preserve/sbtb'}, 'npm-shrinkwrap.json transitive dep')
+ t.done()
+ })
+ })
+})
+
+test('removal', function (t) {
+ t.plan(3)
+ t.test('should remove the symlink')
+ t.test('should not remove the transitive deps if it was not a `link:` type specifier.')
+ t.test("should not remove transitive deps if it's outside the package and --preserver-symlinks isn't set")
+})
+
+test('misc', function (t) {
+ t.plan(3)
+ t.test('listing: should look right, not include version')
+ t.test('outdated: show LOCAL for wanted / latest')
+ t.test('update: if specifier exists, do nothing. otherwise as if `npm install`.')
+})
+
+test('cleanup', function (t) {
+ server.close()
+ cleanup()
+ t.done()
+})