PR-URL: https://github.com/nodejs/node/pull/61892 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
842 lines
22 KiB
JavaScript
842 lines
22 KiB
JavaScript
const t = require('tap')
|
||
const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js')
|
||
|
||
t.cleanSnapshot = str => str
|
||
.replace(/(published ).*?( ago)/g, '$1{TIME}$2')
|
||
|
||
// run the same as tap does when running directly with node
|
||
process.stdout.columns = undefined
|
||
|
||
// 3 days. its never yesterday and never a week ago
|
||
const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 24 * 3)
|
||
|
||
const packument = (nv, opts) => {
|
||
if (!opts.fullMetadata) {
|
||
throw new Error('must fetch fullMetadata')
|
||
}
|
||
|
||
if (!opts.preferOnline) {
|
||
throw new Error('must fetch with preferOnline')
|
||
}
|
||
|
||
const mocks = {
|
||
red: {
|
||
_id: 'red@1.0.1',
|
||
name: 'red',
|
||
'dist-tags': {
|
||
'1.0.1': {},
|
||
},
|
||
time: {
|
||
unpublished: {
|
||
time: '2012-12-20T00:00:00.000Z',
|
||
},
|
||
},
|
||
},
|
||
blue: {
|
||
_id: 'blue',
|
||
name: 'blue',
|
||
'dist-tags': {
|
||
v1: '1.0.0',
|
||
next: '1.0.1',
|
||
prev: '1.0.0',
|
||
latest: '1.0.0',
|
||
a: '1.0.0',
|
||
c: '1.0.0',
|
||
b: '1.0.0',
|
||
d: '1.0.0',
|
||
f: '1.0.1',
|
||
g: '1.0.1',
|
||
h: '1.0.1',
|
||
e: '1.0.1',
|
||
z: '1.0.0',
|
||
x: '1.0.1',
|
||
y: '1.0.0',
|
||
},
|
||
time: {
|
||
'1.0.0': yesterday,
|
||
'1.0.1': '2012-12-20T00:00:00.000Z',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
name: 'blue',
|
||
version: '1.0.0',
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.blue.com/1.0.0.tgz',
|
||
fileCount: 1,
|
||
},
|
||
},
|
||
'1.0.1': {
|
||
name: 'blue',
|
||
version: '1.0.1',
|
||
dist: {
|
||
shasum: '124',
|
||
tarball: 'http://hm.blue.com/1.0.1.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1000,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
// package with no time attribute
|
||
gray: {
|
||
_id: 'gray',
|
||
name: 'gray',
|
||
'dist-tags': {
|
||
latest: '1.1.0',
|
||
beta: '1.2.0-beta',
|
||
alpha: '1.2.0-alpha',
|
||
old: '1.0.0',
|
||
stable: '1.1.0',
|
||
},
|
||
versions: {
|
||
'1.1.0': {
|
||
name: 'gray',
|
||
version: '1.1.0',
|
||
dist: {
|
||
shasum: 'b',
|
||
tarball: 'http://gray/1.1.0.tgz',
|
||
fileCount: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
cyan: {
|
||
_npmUser: {
|
||
name: 'claudia',
|
||
email: 'claudia@cyan.com',
|
||
},
|
||
name: 'cyan',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
name: 'cyan',
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.cyan.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1000000,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
'cyan-oidc': {
|
||
_npmUser: {
|
||
name: 'claudia',
|
||
email: 'claudia@cyan.com',
|
||
trustedPublisher: {
|
||
id: 'github',
|
||
oidcConfigId: 'oidc:a0e127d0-8d66-45d0-8264-e4f8372c7249',
|
||
},
|
||
},
|
||
name: 'cyan',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
name: 'cyan',
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.cyan.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1000000,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
brown: {
|
||
name: 'brown',
|
||
},
|
||
yellow: {
|
||
_id: 'yellow',
|
||
name: 'yellow',
|
||
author: {
|
||
name: 'foo',
|
||
email: 'foo@yellow.com',
|
||
twitter: 'foo',
|
||
},
|
||
empty: '',
|
||
readme: 'a very useful readme',
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
author: 'claudia',
|
||
readme: 'a very useful readme',
|
||
maintainers: [
|
||
{ name: 'claudia', email: 'c@yellow.com', twitter: 'cyellow' },
|
||
{ name: 'isaacs', email: 'i@yellow.com', twitter: 'iyellow' },
|
||
],
|
||
},
|
||
'1.0.1': {
|
||
version: '1.0.1',
|
||
author: 'claudia',
|
||
},
|
||
'1.0.2': {
|
||
version: '1.0.2',
|
||
author: 'claudia',
|
||
},
|
||
},
|
||
},
|
||
purple: {
|
||
name: 'purple',
|
||
versions: {
|
||
'1.0.0': {
|
||
foo: 1,
|
||
maintainers: [
|
||
{ name: 'claudia' },
|
||
],
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
green: {
|
||
_id: 'green',
|
||
name: 'green',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
maintainers: [
|
||
{ name: 'claudia', email: 'c@yellow.com', twitter: 'cyellow' },
|
||
{ name: 'isaacs', email: 'i@yellow.com', twitter: 'iyellow' },
|
||
],
|
||
keywords: ['colors', 'green', 'crayola'],
|
||
versions: {
|
||
'1.0.0': {
|
||
_id: 'green',
|
||
version: '1.0.0',
|
||
description: 'green is a very important color',
|
||
bugs: {
|
||
url: 'http://bugs.green.com',
|
||
},
|
||
deprecated: true,
|
||
repository: {
|
||
url: 'http://repository.green.com',
|
||
},
|
||
license: { type: 'ACME' },
|
||
bin: {
|
||
green: 'bin/green.js',
|
||
},
|
||
dependencies: {
|
||
red: '1.0.0',
|
||
yellow: '1.0.0',
|
||
},
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.green.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1000000000,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
black: {
|
||
name: 'black',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
bugs: 'http://bugs.black.com',
|
||
license: {},
|
||
dependencies: (() => {
|
||
const deps = {}
|
||
for (let i = 0; i < 25; i++) {
|
||
deps[i] = '1.0.0'
|
||
}
|
||
|
||
return deps
|
||
})(),
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.black.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
pink: {
|
||
name: 'pink',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
maintainers: [
|
||
{ name: 'claudia', url: 'http://c.pink.com' },
|
||
{ name: 'isaacs', url: 'http://i.pink.com' },
|
||
],
|
||
repository: 'http://repository.pink.com',
|
||
license: {},
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.pink.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
},
|
||
},
|
||
orange: {
|
||
name: 'orange',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
version: '1.0.0',
|
||
homepage: 'http://hm.orange.com',
|
||
license: {},
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.orange.com/1.0.0.tgz',
|
||
integrity: '---',
|
||
fileCount: 1,
|
||
unpackedSize: 1,
|
||
},
|
||
},
|
||
'1.0.1': {},
|
||
'100000000000000000.0.0': {
|
||
},
|
||
},
|
||
},
|
||
'single-version': {
|
||
_id: 'single-version',
|
||
name: 'single-version',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
name: 'single-version',
|
||
version: '1.0.0',
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.single-version.com/1.0.0.tgz',
|
||
fileCount: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
// this is a packaged named error which will conflict with
|
||
// the error key in json output
|
||
error: {
|
||
_id: 'error',
|
||
name: 'error',
|
||
'dist-tags': {
|
||
latest: '1.0.0',
|
||
},
|
||
versions: {
|
||
'1.0.0': {
|
||
name: 'error',
|
||
version: '1.0.0',
|
||
dist: {
|
||
shasum: '123',
|
||
tarball: 'http://hm.error.com/1.0.0.tgz',
|
||
fileCount: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
if (nv.type === 'git') {
|
||
return mocks[nv.hosted.project]
|
||
}
|
||
|
||
if (nv.raw === './blue') {
|
||
return mocks.blue
|
||
}
|
||
|
||
if (mocks[nv.name]) {
|
||
return mocks[nv.name]
|
||
}
|
||
|
||
if (nv.name === 'unknown-error') {
|
||
throw new Error('Unknown error')
|
||
}
|
||
|
||
throw Object.assign(new Error('404'), { code: 'E404' })
|
||
}
|
||
|
||
const loadMockNpm = async function (t, opts = {}) {
|
||
return _loadMockNpm(t, {
|
||
command: 'view',
|
||
mocks: {
|
||
pacote: {
|
||
packument,
|
||
},
|
||
},
|
||
...opts,
|
||
config: {
|
||
color: 'always',
|
||
...opts.config,
|
||
},
|
||
})
|
||
}
|
||
|
||
t.test('package from git', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['https://github.com/npm/green'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('deprecated package with license, bugs, repository and other fields', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['green@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('deprecated package with unicode', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: true } })
|
||
await view.exec(['green@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with more than 25 deps', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['black@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with maintainers info as object', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['pink@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with homepage', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['orange@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with invalid version', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['orange', 'versions'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with no versions', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['brown'])
|
||
t.equal(joinedOutput(), '', 'no info to display')
|
||
})
|
||
|
||
t.test('package with no repo or homepage', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['blue@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with semver range', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['blue@^1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with no modified time', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } })
|
||
await view.exec(['cyan@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with --json and semver range', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['cyan@^1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('package with _npmUser.trustedPublisher shows cleaned up property with --json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['cyan-oidc@^1.0.0'])
|
||
t.match(joinedOutput(), /claudia <claudia@cyan.com>/, 'uses oidc trustedPublisher info for _npmUser')
|
||
})
|
||
|
||
t.test('package with --json and no versions', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['brown'])
|
||
t.equal(joinedOutput(), '', 'no info to display')
|
||
})
|
||
|
||
t.test('package with --json and single string arg', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['blue', 'dist-tags.latest'])
|
||
t.equal(JSON.parse(joinedOutput()), '1.0.0', 'no info to display')
|
||
})
|
||
|
||
t.test('package with single version', async t => {
|
||
t.test('full json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['single-version'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('json and versions arg', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
|
||
await view.exec(['single-version', 'versions'])
|
||
const parsed = JSON.parse(joinedOutput())
|
||
t.strictSame(parsed, ['1.0.0'], 'does not unwrap single item arrays in json')
|
||
})
|
||
|
||
t.test('no json and versions arg', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: false } })
|
||
await view.exec(['single-version', 'versions'])
|
||
t.strictSame(joinedOutput(), '1.0.0', 'unwraps single item arrays in basic mode')
|
||
})
|
||
})
|
||
|
||
t.test('package in cwd', async t => {
|
||
const prefixDir = {
|
||
'package.json': JSON.stringify({
|
||
name: 'blue',
|
||
version: '1.0.0',
|
||
}, null, 2),
|
||
}
|
||
|
||
t.test('specific version', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { prefixDir })
|
||
await view.exec(['.@1.0.0'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('non-specific version', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { prefixDir })
|
||
await view.exec(['.'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('directory', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { prefixDir })
|
||
await view.exec(['./blue'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
})
|
||
|
||
t.test('specific field names', async t => {
|
||
const { view, joinedOutput, clearOutput } = await loadMockNpm(t, { config: { color: false } })
|
||
t.afterEach(() => clearOutput())
|
||
|
||
t.test('readme', async t => {
|
||
await view.exec(['yellow@1.0.0', 'readme'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('several fields', async t => {
|
||
await view.exec(['yellow@1.0.0', 'name', 'version', 'foo[bar]'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('several fields with several versions', async t => {
|
||
await view.exec(['yellow@1.x.x', 'author'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('nested field with brackets', async t => {
|
||
await view.exec(['orange@1.0.0', 'dist[shasum]'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('maintainers with email', async t => {
|
||
await view.exec(['yellow@1.0.0', 'maintainers', 'name'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('maintainers with url', async t => {
|
||
await view.exec(['pink@1.0.0', 'maintainers'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('unknown nested field ', async t => {
|
||
await view.exec(['yellow@1.0.0', 'dist.foobar'])
|
||
t.equal(joinedOutput(), '', 'no info to display')
|
||
})
|
||
|
||
t.test('array field - 1 element', async t => {
|
||
await view.exec(['purple@1.0.0', 'maintainers.name'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('array field - 2 elements', async t => {
|
||
await view.exec(['yellow@1.x.x', 'maintainers.name'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('fields with empty values', async t => {
|
||
await view.exec(['yellow', 'empty'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
})
|
||
|
||
t.test('throw error if global mode', async t => {
|
||
const { npm } = await loadMockNpm(t, { config: { global: true } })
|
||
await t.rejects(
|
||
npm.exec('view', []),
|
||
/Cannot use view command in global mode./
|
||
)
|
||
})
|
||
|
||
t.test('throw ENOENT error if package.json missing', async t => {
|
||
const { npm } = await loadMockNpm(t)
|
||
await t.rejects(
|
||
npm.exec('view', []),
|
||
{ code: 'ENOENT' }
|
||
)
|
||
})
|
||
|
||
t.test('throw error if package.json has no name', async t => {
|
||
const { npm } = await loadMockNpm(t, {
|
||
prefixDir: {
|
||
'package.json': '{}',
|
||
},
|
||
})
|
||
await t.rejects(
|
||
npm.exec('view', []),
|
||
/Invalid package.json, no "name" field/
|
||
)
|
||
})
|
||
|
||
t.test('throws when unpublished', async t => {
|
||
const { npm } = await loadMockNpm(t)
|
||
await t.rejects(
|
||
npm.exec('view', ['red']),
|
||
{ code: 'E404', pkgid: 'red@1.0.1', message: 'Unpublished on 2012-12-20T00:00:00.000Z' }
|
||
)
|
||
})
|
||
|
||
t.test('throws when version not matched', async t => {
|
||
const { npm } = await loadMockNpm(t)
|
||
await t.rejects(
|
||
npm.exec('view', ['blue@2.0.0']),
|
||
{ code: 'E404', pkgid: 'blue@2.0.0', message: 'No match found for version 2.0.0' }
|
||
)
|
||
})
|
||
|
||
t.test('workspaces', async t => {
|
||
const prefixDir = {
|
||
'package.json': JSON.stringify({
|
||
name: 'workspaces-test-package',
|
||
version: '1.2.3',
|
||
workspaces: ['test-workspace-a', 'test-workspace-b'],
|
||
}),
|
||
'test-workspace-a': {
|
||
'package.json': JSON.stringify({
|
||
name: 'green',
|
||
version: '1.2.3',
|
||
}),
|
||
},
|
||
'test-workspace-b': {
|
||
'package.json': JSON.stringify({
|
||
name: 'orange',
|
||
version: '1.2.3',
|
||
}),
|
||
},
|
||
}
|
||
|
||
const prefixDir404 = {
|
||
'test-workspace-b': {
|
||
'package.json': JSON.stringify({
|
||
name: 'missing-package',
|
||
version: '1.2.3',
|
||
}),
|
||
},
|
||
}
|
||
|
||
const prefixDirError = {
|
||
'test-workspace-b': {
|
||
'package.json': JSON.stringify({
|
||
name: 'unknown-error',
|
||
version: '1.2.3',
|
||
}),
|
||
},
|
||
}
|
||
|
||
const prefixPackageNamedError = {
|
||
'test-workspace-a': {
|
||
'package.json': JSON.stringify({
|
||
name: 'error',
|
||
version: '1.2.3',
|
||
}),
|
||
},
|
||
}
|
||
|
||
t.test('all workspaces', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('one specific workspace', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspace: ['green'] },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('all workspaces --json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true, json: true },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('all workspaces single field', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true },
|
||
})
|
||
await view.exec(['.', 'name'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('all workspaces nonexistent field', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true },
|
||
})
|
||
await view.exec(['.', 'foo'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('all workspaces nonexistent field --json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true, json: true },
|
||
})
|
||
await view.exec(['.', 'foo'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('all workspaces single field --json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true, json: true },
|
||
})
|
||
await view.exec(['.', 'name'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('single workspace --json', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspace: ['green'], json: true },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('remote package name', async t => {
|
||
const { view, logs, joinedOutput } = await loadMockNpm(t, {
|
||
prefixDir,
|
||
config: { unicode: false, workspaces: true },
|
||
})
|
||
await view.exec(['pink'])
|
||
t.matchSnapshot(joinedOutput())
|
||
t.matchSnapshot(logs.warn, 'should have warning of ignoring workspaces')
|
||
})
|
||
|
||
t.test('404 workspaces', async t => {
|
||
t.test('basic', async t => {
|
||
const { view, joinedFullOutput } = await loadMockNpm(t, {
|
||
prefixDir: { ...prefixDir, ...prefixDir404 },
|
||
config: { workspaces: true, loglevel: 'error' },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedFullOutput())
|
||
t.equal(process.exitCode, 1)
|
||
})
|
||
|
||
t.test('json', async t => {
|
||
const { view, joinedFullOutput } = await loadMockNpm(t, {
|
||
prefixDir: { ...prefixDir, ...prefixDir404 },
|
||
config: { workspaces: true, json: true, loglevel: 'error' },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedFullOutput())
|
||
t.equal(process.exitCode, 1)
|
||
})
|
||
|
||
t.test('json with package named error', async t => {
|
||
const { view, joinedFullOutput } = await loadMockNpm(t, {
|
||
prefixDir: { ...prefixDir, ...prefixDir404, ...prefixPackageNamedError },
|
||
config: { workspaces: true, json: true, loglevel: 'warn' },
|
||
})
|
||
await view.exec([])
|
||
t.matchSnapshot(joinedFullOutput())
|
||
t.equal(process.exitCode, 1)
|
||
})
|
||
|
||
t.test('non-404 error rejects', async t => {
|
||
const { view, joinedFullOutput } = await loadMockNpm(t, {
|
||
prefixDir: { ...prefixDir, ...prefixDirError },
|
||
config: { workspaces: true, loglevel: 'error' },
|
||
})
|
||
await t.rejects(view.exec([]))
|
||
t.matchSnapshot(joinedFullOutput())
|
||
})
|
||
|
||
t.test('non-404 error rejects with single arg', async t => {
|
||
const { view, joinedFullOutput } = await loadMockNpm(t, {
|
||
prefixDir: { ...prefixDir, ...prefixDirError },
|
||
config: { workspaces: true, loglevel: 'error' },
|
||
})
|
||
await t.rejects(view.exec(['.', 'version']))
|
||
t.matchSnapshot(joinedFullOutput())
|
||
})
|
||
})
|
||
})
|
||
|
||
t.test('completion', async t => {
|
||
const { view } = await loadMockNpm(t, { command: 'view' })
|
||
const res = await view.completion({
|
||
conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } },
|
||
})
|
||
t.ok(res, 'returns back fields')
|
||
})
|
||
|
||
t.test('no package completion', async t => {
|
||
const { view } = await loadMockNpm(t, { command: 'view' })
|
||
const res = await view.completion({ conf: { argv: { remain: ['npm', 'view'] } } })
|
||
t.notOk(res, 'there is no package completion')
|
||
t.end()
|
||
})
|
||
|
||
t.test('allow-git=root, package with multiple dist‑tags and no time', async t => {
|
||
const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false, 'allow-git': 'root' } })
|
||
await view.exec(['https://github.com/npm/gray'])
|
||
t.matchSnapshot(joinedOutput())
|
||
})
|
||
|
||
t.test('allow-git=none', async t => {
|
||
const { view } = await loadMockNpm(t, { config: { 'allow-git': 'none' }, mocks: {} })
|
||
await t.rejects(view.exec(['npm/npm']), {
|
||
code: 'EALLOWGIT',
|
||
package: 'github:npm/npm',
|
||
message: 'Fetching packages of type "git" have been disabled',
|
||
})
|
||
})
|