summaryrefslogtreecommitdiff
path: root/deps/npm/test/tap/search.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/test/tap/search.js')
-rw-r--r--deps/npm/test/tap/search.js545
1 files changed, 309 insertions, 236 deletions
diff --git a/deps/npm/test/tap/search.js b/deps/npm/test/tap/search.js
index 138517c3bd..dcc46df78e 100644
--- a/deps/npm/test/tap/search.js
+++ b/deps/npm/test/tap/search.js
@@ -1,81 +1,185 @@
-var fs = require('graceful-fs')
var path = require('path')
-
var mkdirp = require('mkdirp')
-var mr = require('npm-registry-mock')
var osenv = require('osenv')
var rimraf = require('rimraf')
+var cacheFile = require('npm-cache-filename')
var test = require('tap').test
+var Tacks = require('tacks')
+var File = Tacks.File
var common = require('../common-tap.js')
-var pkg = path.resolve(__dirname, 'search')
-var cache = path.resolve(pkg, 'cache')
-var registryCache = path.resolve(cache, 'localhost_1337', '-', 'all')
-var cacheJsonFile = path.resolve(registryCache, '.cache.json')
-
-var timeMock = {
- epoch: 1411727900,
- future: 1411727900 + 100,
- all: 1411727900 + 25,
- since: 0 // filled by since server callback
-}
+var PKG_DIR = path.resolve(__dirname, 'search')
+var CACHE_DIR = path.resolve(PKG_DIR, 'cache')
+var cacheBase = cacheFile(CACHE_DIR)(common.registry + '/-/all')
+var cachePath = path.join(cacheBase, '.cache.json')
-var EXEC_OPTS = {}
+test('setup', function (t) {
+ t.pass('all set up')
+ t.done()
+})
-var mocks = {
- /* Since request, always response with an _update time > the time requested */
- sinceFuture: function (server) {
- server.filteringPathRegEx(/startkey=[^&]*/g, function (s) {
- var _allMock = JSON.parse(JSON.stringify(allMock))
- timeMock.since = _allMock._updated = s.replace('startkey=', '')
- server.get('/-/all/since?stale=update_after&' + s)
- .reply(200, _allMock)
- return s
- })
- },
- allFutureUpdatedOnly: function (server) {
- server.get('/-/all')
- .reply(200, stringifyUpdated(timeMock.future))
- },
- all: function (server) {
- server.get('/-/all')
- .reply(200, allMock)
+test('notifies when there are no results', function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '1.0.0' },
+ foo: { name: 'foo', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
}
-}
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'nomatcheswhatsoeverfromthis',
+ '--registry', common.registry,
+ '--loglevel', 'error',
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.equal(stderr, '', 'no error output')
+ t.equal(code, 0, 'search gives 0 error code even if no matches')
+ t.match(stdout, /No matches found/, 'Useful message on search failure')
+ t.done()
+ })
+})
-test('No previous cache, init cache triggered by first search', function (t) {
- cleanup()
+test('spits out a useful error when no cache nor network', function (t) {
+ setup()
+ var cacheContents = {}
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'foo',
+ '--registry', common.registry,
+ '--loglevel', 'silly',
+ '--fetch-retry-mintimeout', 0,
+ '--fetch-retry-maxtimeout', 0,
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.equal(code, 1, 'non-zero exit code')
+ t.equal(stdout, '', 'no stdout output')
+ t.match(stderr, /No search sources available/, 'useful error')
+ t.done()
+ })
+})
- mr({ port: common.port, plugin: mocks.allFutureUpdatedOnly }, function (err, s) {
- t.ifError(err, 'mock registry started')
- common.npm([
- 'search', 'do not do extra search work on my behalf',
- '--registry', common.registry,
- '--cache', cache,
- '--loglevel', 'silent',
- '--color', 'always'
- ],
- EXEC_OPTS,
- function (err, code) {
- s.close()
- t.equal(code, 0, 'search finished successfully')
- t.ifErr(err, 'search finished successfully')
+test('can switch to JSON mode', function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '1.0.0' },
+ foo: { name: 'foo', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
+ }
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'oo',
+ '--json',
+ '--registry', common.registry,
+ '--loglevel', 'error',
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.deepEquals(JSON.parse(stdout), [
+ { name: 'cool', version: '1.0.0' },
+ { name: 'foo', version: '2.0.0' }
+ ], 'results returned as valid json')
+ t.equal(stderr, '', 'no error output')
+ t.equal(code, 0, 'search gives 0 error code even if no matches')
+ t.done()
+ })
+})
- t.ok(
- fs.existsSync(cacheJsonFile),
- cacheJsonFile + ' expected to have been created'
- )
+test('JSON mode does not notify on empty', function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '1.0.0' },
+ foo: { name: 'foo', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
+ }
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'nomatcheswhatsoeverfromthis',
+ '--json',
+ '--registry', common.registry,
+ '--loglevel', 'error',
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.deepEquals(JSON.parse(stdout), [], 'no notification about no results')
+ t.equal(stderr, '', 'no error output')
+ t.equal(code, 0, 'search gives 0 error code even if no matches')
+ t.done()
+ })
+})
- var cacheData = JSON.parse(fs.readFileSync(cacheJsonFile, 'utf8'))
- t.equal(cacheData._updated, String(timeMock.future))
- t.end()
- })
+test('can switch to tab separated mode', function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '1.0.0' },
+ foo: { name: 'foo', description: 'this\thas\ttabs', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
+ }
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'oo',
+ '--parseable',
+ '--registry', common.registry,
+ '--loglevel', 'error',
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.equal(stdout, 'cool\t\t\tprehistoric\t\t\nfoo\tthis has tabs\t\tprehistoric\t\t\n', 'correct output, including replacing tabs in descriptions')
+ t.equal(stderr, '', 'no error output')
+ t.equal(code, 0, 'search gives 0 error code even if no matches')
+ t.done()
+ })
+})
+
+test('tab mode does not notify on empty', function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '1.0.0' },
+ foo: { name: 'foo', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
+ }
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', 'nomatcheswhatsoeverfromthis',
+ '--parseable',
+ '--registry', common.registry,
+ '--loglevel', 'error',
+ '--cache', CACHE_DIR
+ ], {}, function (err, code, stdout, stderr) {
+ if (err) throw err
+ t.equal(stdout, '', 'no notification about no results')
+ t.equal(stderr, '', 'no error output')
+ t.equal(code, 0, 'search gives 0 error code even if no matches')
+ t.done()
})
})
test('no arguments provided should error', function (t) {
- common.npm(['search'], [], function (err, code, stdout, stderr) {
+ cleanup()
+ common.npm(['search'], {}, function (err, code, stdout, stderr) {
if (err) throw err
t.equal(code, 1, 'search finished unsuccessfully')
@@ -88,83 +192,157 @@ test('no arguments provided should error', function (t) {
})
})
-test('previous cache, _updated set, should trigger since request', function (t) {
- setupCache()
-
- function m (server) {
- [ mocks.all, mocks.sinceFuture ].forEach(function (m) {
- m(server)
- })
- }
- mr({ port: common.port, plugin: m }, function (err, s) {
- t.ifError(err, 'mock registry started')
- common.npm([
- 'search', 'do not do extra search work on my behalf',
- '--registry', common.registry,
- '--cache', cache,
- '--loglevel', 'silly',
- '--color', 'always'
- ],
- EXEC_OPTS,
- function (err, code) {
- s.close()
- t.equal(code, 0, 'search finished successfully')
- t.ifErr(err, 'search finished successfully')
-
- var cacheData = JSON.parse(fs.readFileSync(cacheJsonFile, 'utf8'))
- t.equal(
- cacheData._updated,
- timeMock.since,
- 'cache update time gotten from since response'
- )
- t.end()
- })
- })
-})
-
var searches = [
{
- term: 'f36b6a6123da50959741e2ce4d634f96ec668c56',
- description: 'non-regex',
- location: 241
+ term: 'cool',
+ description: 'non-regex search',
+ location: 103
+ },
+ {
+ term: '/cool/',
+ description: 'regex search',
+ location: 103
},
{
- term: '/f36b6a6123da50959741e2ce4d634f96ec668c56/',
- description: 'regex',
- location: 241
+ term: 'cool',
+ description: 'searches name field',
+ location: 103
+ },
+ {
+ term: 'ool',
+ description: 'excludes matches for --searchexclude',
+ location: 205,
+ inject: {
+ other: { name: 'other', description: 'this is a simple tool' }
+ },
+ extraOpts: ['--searchexclude', 'cool']
+ },
+ {
+ term: 'neat lib',
+ description: 'searches description field',
+ location: 141,
+ inject: {
+ cool: {
+ name: 'cool', version: '5.0.0', description: 'this is a neat lib'
+ }
+ }
+ },
+ {
+ term: 'foo',
+ description: 'skips description field with --no-description',
+ location: 80,
+ inject: {
+ cool: {
+ name: 'cool', version: '5.0.0', description: 'foo bar!'
+ }
+ },
+ extraOpts: ['--no-description']
+ },
+ {
+ term: 'zkat',
+ description: 'searches maintainers by name',
+ location: 155,
+ inject: {
+ cool: {
+ name: 'cool',
+ version: '5.0.0',
+ maintainers: [{
+ name: 'zkat'
+ }]
+ }
+ }
+ },
+ {
+ term: '=zkat',
+ description: 'searches maintainers unambiguously by =name',
+ location: 154,
+ inject: {
+ bar: { name: 'bar', description: 'zkat thing', version: '1.0.0' },
+ cool: {
+ name: 'cool',
+ version: '5.0.0',
+ maintainers: [{
+ name: 'zkat'
+ }]
+ }
+ }
+ },
+ {
+ term: 'github.com',
+ description: 'searches projects by url',
+ location: 205,
+ inject: {
+ bar: {
+ name: 'bar',
+ url: 'gitlab.com/bar',
+ // For historical reasons, `url` is only present if `versions` is there
+ versions: ['1.0.0'],
+ version: '1.0.0'
+ },
+ cool: {
+ name: 'cool',
+ version: '5.0.0',
+ versions: ['1.0.0'],
+ url: 'github.com/cool/cool'
+ }
+ }
+ },
+ {
+ term: 'monad',
+ description: 'searches projects by keywords',
+ location: 197,
+ inject: {
+ cool: {
+ name: 'cool',
+ version: '5.0.0',
+ keywords: ['monads']
+ }
+ }
}
]
searches.forEach(function (search) {
- test(search.description + ' search in color', function (t) {
- cleanup()
- mr({ port: common.port, plugin: mocks.all }, function (er, s) {
- common.npm([
- 'search', search.term,
- '--registry', common.registry,
- '--cache', cache,
- '--loglevel', 'silent',
- '--color', 'always'
- ],
- EXEC_OPTS,
- function (err, code, stdout) {
- s.close()
- t.equal(code, 0, 'search finished successfully')
- t.ifErr(err, 'search finished successfully')
- // \033 == \u001B
- var markStart = '\u001B\\[[0-9][0-9]m'
- var markEnd = '\u001B\\[0m'
+ test(search.description, function (t) {
+ setup()
+ var now = Date.now()
+ var cacheContents = {
+ '_updated': now,
+ bar: { name: 'bar', version: '1.0.0' },
+ cool: { name: 'cool', version: '5.0.0' },
+ foo: { name: 'foo', version: '2.0.0' },
+ other: { name: 'other', version: '1.0.0' }
+ }
+ for (var k in search.inject) {
+ cacheContents[k] = search.inject[k]
+ }
+ var fixture = new Tacks(File(cacheContents))
+ fixture.create(cachePath)
+ common.npm([
+ 'search', search.term,
+ '--registry', common.registry,
+ '--cache', CACHE_DIR,
+ '--loglevel', 'error',
+ '--color', 'always'
+ ].concat(search.extraOpts || []),
+ {},
+ function (err, code, stdout, stderr) {
+ t.equal(stderr, '', 'no error output')
+ t.notEqual(stdout, '', 'got output')
+ t.equal(code, 0, 'search finished successfully')
+ t.ifErr(err, 'search finished successfully')
+ // \033 == \u001B
+ var markStart = '\u001B\\[[0-9][0-9]m'
+ var markEnd = '\u001B\\[0m'
- var re = new RegExp(markStart + '.*?' + markEnd)
+ var re = new RegExp(markStart + '.*?' + markEnd)
- var cnt = stdout.search(re)
- t.equal(
- cnt,
- search.location,
- search.description + ' search for ' + search.term
- )
- t.end()
- })
+ var cnt = stdout.search(re)
+ t.equal(
+ cnt,
+ search.location,
+ search.description + ' search for ' + search.term
+ )
+ t.end()
})
})
})
@@ -174,117 +352,12 @@ test('cleanup', function (t) {
t.end()
})
-function cleanup () {
- process.chdir(osenv.tmpdir())
- rimraf.sync(pkg)
-}
-
-function setupCache () {
+function setup () {
cleanup()
- mkdirp.sync(cache)
- mkdirp.sync(registryCache)
- var res = fs.writeFileSync(cacheJsonFile, stringifyUpdated(timeMock.epoch))
- if (res) throw new Error('Creating cache file failed')
+ mkdirp.sync(cacheBase)
}
-function stringifyUpdated (time) {
- return JSON.stringify({ _updated: String(time) })
-}
-
-var allMock = {
- '_updated': timeMock.all,
- 'generator-frontcow': {
- 'name': 'generator-frontcow',
- 'description': 'f36b6a6123da50959741e2ce4d634f96ec668c56 This is a fake description to ensure we do not accidentally search the real npm registry or use some kind of cache',
- 'dist-tags': {
- 'latest': '0.1.19'
- },
- 'maintainers': [
- {
- 'name': 'bcabanes',
- 'email': 'contact@benjamincabanes.com'
- }
- ],
- 'homepage': 'https://github.com/bcabanes/generator-frontcow',
- 'keywords': [
- 'sass',
- 'frontend',
- 'yeoman-generator',
- 'atomic',
- 'design',
- 'sass',
- 'foundation',
- 'foundation5',
- 'atomic design',
- 'bourbon',
- 'polyfill',
- 'font awesome'
- ],
- 'repository': {
- 'type': 'git',
- 'url': 'https://github.com/bcabanes/generator-frontcow'
- },
- 'author': {
- 'name': 'ben',
- 'email': 'contact@benjamincabanes.com',
- 'url': 'https://github.com/bcabanes'
- },
- 'bugs': {
- 'url': 'https://github.com/bcabanes/generator-frontcow/issues'
- },
- 'license': 'MIT',
- 'readmeFilename': 'README.md',
- 'time': {
- 'modified': '2014-10-03T02:26:18.406Z'
- },
- 'versions': {
- '0.1.19': 'latest'
- }
- },
- 'marko': {
- 'name': 'marko',
- 'description': 'Marko is an extensible, streaming, asynchronous, high performance, HTML-based templating language that can be used in Node.js or in the browser.',
- 'dist-tags': {
- 'latest': '1.2.16'
- },
- 'maintainers': [
- {
- 'name': 'pnidem',
- 'email': 'pnidem@gmail.com'
- },
- {
- 'name': 'philidem',
- 'email': 'phillip.idem@gmail.com'
- }
- ],
- 'homepage': 'https://github.com/raptorjs/marko',
- 'keywords': [
- 'templating',
- 'template',
- 'async',
- 'streaming'
- ],
- 'repository': {
- 'type': 'git',
- 'url': 'https://github.com/raptorjs/marko.git'
- },
- 'author': {
- 'name': 'Patrick Steele-Idem',
- 'email': 'pnidem@gmail.com'
- },
- 'bugs': {
- 'url': 'https://github.com/raptorjs/marko/issues'
- },
- 'license': 'Apache License v2.0',
- 'readmeFilename': 'README.md',
- 'users': {
- 'pnidem': true
- },
- 'time': {
- 'modified': '2014-10-03T02:27:31.775Z'
- },
- 'versions': {
- '1.2.16': 'latest'
- }
- }
+function cleanup () {
+ process.chdir(osenv.tmpdir())
+ rimraf.sync(PKG_DIR)
}