Skip to content

Commit

Permalink
fix: remove test coverage map (npm#4862)
Browse files Browse the repository at this point in the history
Turns out there were three files that still had no test coverage because
of the combination of the mocks in tests and the coverage map.  Removing
the map altogether exposed them.

This PR removes the coverage map and fixes test to cover all lines that
were being missed.

While adding coverage to the `npm search` codebase multiple unneeded
guards and at least one bug was found (it was impossible to exclude
searches based on username). These were fixed.

The `npm view` tests were also refactored to use the real npm object.

Finally, a small inlining of lib/utils/file-exists.js was done.
wraithgar authored May 7, 2022

Verified

This commit was signed with the committer’s verified signature.
aymanbagabas Ayman Bagabas
1 parent 8e7ea9b commit 48d2db6
Showing 19 changed files with 729 additions and 861 deletions.
18 changes: 12 additions & 6 deletions lib/commands/completion.js
Original file line number Diff line number Diff line change
@@ -29,18 +29,26 @@
// as an array.
//

const fs = require('@npmcli/fs')
const nopt = require('nopt')

const { definitions, shorthands } = require('../utils/config/index.js')
const { aliases, cmdList, plumbing } = require('../utils/cmd-list.js')
const aliasNames = Object.keys(aliases)
const fullList = cmdList.concat(aliasNames).filter(c => !plumbing.includes(c))
const nopt = require('nopt')
const configNames = Object.keys(definitions)
const shorthandNames = Object.keys(shorthands)
const allConfs = configNames.concat(shorthandNames)
const { isWindowsShell } = require('../utils/is-windows.js')
const fileExists = require('../utils/file-exists.js')
const fileExists = async (file) => {
try {
const stat = await fs.stat(file)
return stat.isFile()
} catch {
return false
}
}

const { promisify } = require('util')
const BaseCommand = require('../base-command.js')

class Completion extends BaseCommand {
@@ -189,12 +197,10 @@ class Completion extends BaseCommand {
}

const dumpScript = async () => {
const fs = require('fs')
const readFile = promisify(fs.readFile)
const { resolve } = require('path')
const p = resolve(__dirname, '..', 'utils', 'completion.sh')

const d = (await readFile(p, 'utf8')).replace(/^#!.*?\n/, '')
const d = (await fs.readFile(p, 'utf8')).replace(/^#!.*?\n/, '')
await new Promise((res, rej) => {
let done = false
process.stdout.on('error', er => {
47 changes: 27 additions & 20 deletions lib/commands/search.js
Original file line number Diff line number Diff line change
@@ -3,26 +3,33 @@ const Pipeline = require('minipass-pipeline')
const libSearch = require('libnpmsearch')
const log = require('../utils/log-shim.js')

const formatPackageStream = require('../search/format-package-stream.js')
const packageFilter = require('../search/package-filter.js')
const formatSearchStream = require('../utils/format-search-stream.js')

function filter (data, include, exclude) {
const words = [data.name]
.concat(data.maintainers.map(m => `=${m.username}`))
.concat(data.keywords || [])
.map(f => f && f.trim && f.trim())
.filter(f => f)
.join(' ')
.toLowerCase()

if (exclude.find(e => match(words, e))) {
return false
}

function prepareIncludes (args) {
return args
.map(s => s.toLowerCase())
.filter(s => s)
return true
}

function prepareExcludes (searchexclude) {
var exclude
if (typeof searchexclude === 'string') {
exclude = searchexclude.split(/\s+/)
} else {
exclude = []
function match (words, pattern) {
if (pattern.startsWith('/')) {
if (pattern.endsWith('/')) {
pattern = pattern.slice(0, -1)
}
pattern = new RegExp(pattern.slice(1))
return words.match(pattern)
}

return exclude
.map(s => s.toLowerCase())
.filter(s => s)
return words.indexOf(pattern) !== -1
}

const BaseCommand = require('../base-command.js')
@@ -50,8 +57,8 @@ class Search extends BaseCommand {
const opts = {
...this.npm.flatOptions,
...this.npm.flatOptions.search,
include: prepareIncludes(args),
exclude: prepareExcludes(this.npm.flatOptions.search.exclude),
include: args.map(s => s.toLowerCase()).filter(s => s),
exclude: this.npm.flatOptions.search.exclude.split(/\s+/),
}

if (opts.include.length === 0) {
@@ -63,7 +70,7 @@ class Search extends BaseCommand {

class FilterStream extends Minipass {
write (pkg) {
if (packageFilter(pkg, opts.include, opts.exclude)) {
if (filter(pkg, opts.include, opts.exclude)) {
super.write(pkg)
}
}
@@ -73,7 +80,7 @@ class Search extends BaseCommand {

// Grab a configured output stream that will spit out packages in the
// desired format.
const outputStream = formatPackageStream({
const outputStream = formatSearchStream({
args, // --searchinclude options are not highlighted
...opts,
})
3 changes: 0 additions & 3 deletions lib/commands/view.js
Original file line number Diff line number Diff line change
@@ -57,9 +57,6 @@ class View extends BaseCommand {

function getFields (d, f, pref) {
f = f || []
if (!d) {
return f
}
pref = pref || []
Object.keys(d).forEach((k) => {
if (k.charAt(0) === '_' || k.indexOf('.') !== -1) {
43 changes: 0 additions & 43 deletions lib/search/package-filter.js

This file was deleted.

2 changes: 1 addition & 1 deletion lib/utils/config/definitions.js
Original file line number Diff line number Diff line change
@@ -1856,7 +1856,7 @@ define('searchexclude', {
`,
flatten (key, obj, flatOptions) {
flatOptions.search = flatOptions.search || { limit: 20 }
flatOptions.search.exclude = obj[key]
flatOptions.search.exclude = obj[key].toLowerCase()
},
})

10 changes: 0 additions & 10 deletions lib/utils/file-exists.js

This file was deleted.

1 change: 1 addition & 0 deletions lib/utils/format-bytes.js
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ const formatBytes = (bytes, space = true) => {
return `${(bytes / 1000000).toFixed(1)}${spacer}MB`
}

// GB
return `${(bytes / 1000000000).toFixed(1)}${spacer}GB`
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// XXX these output classes should not live in here forever. it'd be good to
// split them out, perhaps to libnpmsearch

const Minipass = require('minipass')
const columnify = require('columnify')

@@ -18,32 +15,26 @@ const columnify = require('columnify')
// The returned stream will format this package data
// into a byte stream of formatted, displayable output.

module.exports = (opts = {}) =>
opts.json ? new JSONOutputStream() : new TextOutputStream(opts)
module.exports = (opts) => {
return opts.json ? new JSONOutputStream() : new TextOutputStream(opts)
}

class JSONOutputStream extends Minipass {
constructor () {
super()
this._didFirst = false
}
#didFirst = false

write (obj) {
if (!this._didFirst) {
if (!this.#didFirst) {
super.write('[\n')
this._didFirst = true
this.#didFirst = true
} else {
super.write('\n,\n')
}

try {
return super.write(JSON.stringify(obj))
} catch (er) {
return this.emit('error', er)
}
return super.write(JSON.stringify(obj))
}

end () {
super.write(this._didFirst ? ']\n' : '\n[]\n')
super.write(this.#didFirst ? ']\n' : '\n[]\n')
super.end()
}
}
@@ -61,22 +52,22 @@ class TextOutputStream extends Minipass {
}

function prettify (data, num, opts) {
opts = opts || {}
var truncate = !opts.long

var pkg = normalizePackage(data, opts)

var columns = opts.description
? ['name', 'description', 'author', 'date', 'version', 'keywords']
: ['name', 'author', 'date', 'version', 'keywords']
var columns = ['name', 'description', 'author', 'date', 'version', 'keywords']

if (opts.parseable) {
return columns.map(function (col) {
return pkg[col] && ('' + pkg[col]).replace(/\t/g, ' ')
}).join('\t')
}

var output = columnify(
// stdout in tap is never a tty
/* istanbul ignore next */
const maxWidth = process.stdout.isTTY ? process.stdout.getWindowSize()[0] : Infinity
let output = columnify(
[pkg],
{
include: columns,
@@ -92,8 +83,8 @@ function prettify (data, num, opts) {
keywords: { maxWidth: Infinity },
},
}
)
output = trimToMaxWidth(output)
).split('\n').map(line => line.slice(0, maxWidth)).join('\n')

if (opts.color) {
output = highlightSearchTerms(output, opts.args)
}
@@ -140,26 +131,6 @@ function colorize (line) {
return line.split('\u0000').join(uncolor)
}

function getMaxWidth () {
var cols
try {
var tty = require('tty')
var stdout = process.stdout
cols = !tty.isatty(stdout.fd) ? Infinity : process.stdout.getWindowSize()[0]
cols = (cols === 0) ? Infinity : cols
} catch (ex) {
cols = Infinity
}
return cols
}

function trimToMaxWidth (str) {
var maxWidth = getMaxWidth()
return str.split('\n').map(function (line) {
return line.slice(0, maxWidth)
}).join('\n')
}

function highlightSearchTerms (str, terms) {
terms.forEach(function (arg, i) {
str = addColorMarker(str, arg, i)
@@ -169,13 +140,10 @@ function highlightSearchTerms (str, terms) {
}

function normalizePackage (data, opts) {
opts = opts || {}
return {
name: data.name,
description: opts.description ? data.description : '',
author: (data.maintainers || []).map(function (m) {
return '=' + m.username
}).join(' '),
description: data.description,
author: data.maintainers.map((m) => `=${m.username}`).join(' '),
keywords: Array.isArray(data.keywords)
? data.keywords.join(' ')
: typeof data.keywords === 'string'
9 changes: 0 additions & 9 deletions lib/utils/read-package-name.js

This file was deleted.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -230,8 +230,13 @@
],
"color": 1,
"files": "test/{lib,bin,index.js}",
"coverage-map": "test/coverage-map.js",
"timeout": 600
"timeout": 600,
"nyc-arg": [
"--exclude",
"workspaces/**",
"--exclude",
"tap-snapshots/**"
]
},
"templateOSS": {
"rootRepo": false,
130 changes: 124 additions & 6 deletions tap-snapshots/test/lib/commands/search.js.test.cjs
Original file line number Diff line number Diff line change
@@ -9,12 +9,130 @@ exports[`test/lib/commands/search.js TAP empty search results > should have expe
No matches found for "foo"
`

exports[`test/lib/commands/search.js TAP search <name> --searchexclude --searchopts > should have filtered expected search results 1`] = `
NAME | AUTHOR | DATE | VERSION | KEYWORDS
foo | =foo | prehistoric | 1.0.0 |
exports[`test/lib/commands/search.js TAP search /<name>/--color > should have expected search results with color 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 |
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 |
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
libnpmversion | library to do the… | =nlf… | 2020-11-04 | 1.0.7 |
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`

exports[`test/lib/commands/search.js TAP search <name> > should have expected search results 1`] = `
NAME | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager liblibnpmaccess | =nlf… | 2020-11-03 | 4.0.1 | @evocateur/libnpmaccess | =evocateur | 2019-07-16 | 3.1.2 | @evocateur/libnpmpublish | =evocateur | 2019-07-16 | 1.2.2 | libnpmorg | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teamslibnpmsearch | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpmlibnpmteam | =nlf… | 2020-11-03 | 2.0.2 | libnpmhook | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm apilibnpmpublish | =nlf… | 2020-11-03 | 4.0.0 | libnpmfund | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund@npmcli/map-workspaces | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaceslibnpmversion | =nlf… | 2020-11-04 | 1.0.7 | @types/libnpmsearch | =types | 2019-09-26 | 2.0.1 |
exports[`test/lib/commands/search.js TAP search <name> --color > should have expected search results with color 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 | 
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 | 
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 | 
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 | 
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
libnpmversion | library to do the… | =nlf… | 2020-11-04 | 1.0.7 | 
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 | 
`

exports[`test/lib/commands/search.js TAP search <name> --parseable > should have expected search results as parseable 1`] = `
libnpm Collection of programmatic APIs for the npm CLI =nlf =ruyadorno =darcyclarke =isaacs 2019-07-16 3.0.1 npm api package manager lib
libnpmaccess programmatic library for \`npm access\` commands =nlf =ruyadorno =darcyclarke =isaacs 2020-11-03 4.0.1 libnpmaccess
@evocateur/libnpmaccess programmatic library for \`npm access\` commands =evocateur 2019-07-16 3.1.2
@evocateur/libnpmpublish Programmatic API for the bits behind npm publish and unpublish =evocateur 2019-07-16 1.2.2
libnpmorg Programmatic api for \`npm org\` commands =nlf =ruyadorno =darcyclarke =isaacs 2020-11-03 2.0.1 libnpm npm package manager api orgs teams
libnpmsearch Programmatic API for searching in npm and compatible registries. =nlf =ruyadorno =darcyclarke =isaacs 2020-12-08 3.1.0 npm search api libnpm
libnpmteam npm Team management APIs =nlf =ruyadorno =darcyclarke =isaacs 2020-11-03 2.0.2
libnpmhook programmatic API for managing npm registry hooks =nlf =ruyadorno =darcyclarke =isaacs 2020-11-03 6.0.1 npm hooks registry npm api
libnpmpublish Programmatic API for the bits behind npm publish and unpublish =nlf =ruyadorno =darcyclarke =isaacs 2020-11-03 4.0.0
libnpmfund Programmatic API for npm fund =nlf =ruyadorno =darcyclarke =isaacs 2020-12-08 1.0.2 npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces Retrieves a name:pathname Map for a given workspaces config =nlf =ruyadorno =darcyclarke =isaacs 2020-09-30 1.0.1 npm npmcli libnpm cli workspaces map-workspaces
libnpmversion library to do the things that 'npm version' does =nlf =ruyadorno =darcyclarke =isaacs 2020-11-04 1.0.7
@types/libnpmsearch TypeScript definitions for libnpmsearch =types 2019-09-26 2.0.1
`

exports[`test/lib/commands/search.js TAP search <name> > should have filtered expected search results 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
foo | | =foo | prehistoric | 1.0.0 |
libnpmversion | | =foo | prehistoric | 1.0.0 |
`

exports[`test/lib/commands/search.js TAP search <name> text > should have expected search results 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 |
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 |
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
libnpmversion | library to do the… | =nlf… | 2020-11-04 | 1.0.7 |
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`

exports[`test/lib/commands/search.js TAP search exclude forward slash > results should not have libnpmversion 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 |
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 |
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`

exports[`test/lib/commands/search.js TAP search exclude regex > results should not have libnpmversion 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 |
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 |
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`

exports[`test/lib/commands/search.js TAP search exclude string > results should not have libnpmversion 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
libnpm | Collection of… | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager lib
libnpmaccess | programmatic… | =nlf… | 2020-11-03 | 4.0.1 | libnpmaccess
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
libnpmorg | Programmatic api… | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teams
libnpmsearch | Programmatic API… | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpm
libnpmteam | npm Team management… | =nlf… | 2020-11-03 | 2.0.2 |
libnpmhook | programmatic API… | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm api
libnpmpublish | Programmatic API… | =nlf… | 2020-11-03 | 4.0.0 |
libnpmfund | Programmatic API… | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund
@npmcli/map-workspaces | Retrieves a… | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaces
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`

exports[`test/lib/commands/search.js TAP search exclude username with upper case letters > results should not have nlf 1`] = `
NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
@evocateur/libnpmaccess | programmatic… | =evocateur | 2019-07-16 | 3.1.2 |
@evocateur/libnpmpublish | Programmatic API… | =evocateur | 2019-07-16 | 1.2.2 |
@types/libnpmsearch | TypeScript… | =types | 2019-09-26 | 2.0.1 |
`
386 changes: 188 additions & 198 deletions tap-snapshots/test/lib/commands/view.js.test.cjs

Large diffs are not rendered by default.

26 changes: 0 additions & 26 deletions test/coverage-map.js

This file was deleted.

27 changes: 14 additions & 13 deletions test/fixtures/libnpmsearch-stream-result.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ module.exports = [
version: '3.0.1',
description: 'Collection of programmatic APIs for the npm CLI',
keywords: ['npm', 'api', 'package manager', 'lib'],
date: new Date('2019-07-16T17:50:00.572Z'),
date: '2019-07-16T17:50:00.572Z',
links: {
npm: 'https://www.npmjs.com/package/libnpm',
homepage: 'https://github.com/npm/libnpm#readme',
@@ -26,7 +26,8 @@ module.exports = [
scope: 'unscoped',
version: '4.0.1',
description: 'programmatic library for `npm access` commands',
date: new Date('2020-11-03T19:19:00.526Z'),
keywords: 'libnpmaccess',
date: '2020-11-03T19:19:00.526Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmaccess',
homepage: 'https://npmjs.com/package/libnpmaccess',
@@ -47,7 +48,7 @@ module.exports = [
scope: 'evocateur',
version: '3.1.2',
description: 'programmatic library for `npm access` commands',
date: new Date('2019-07-16T19:43:33.959Z'),
date: '2019-07-16T19:43:33.959Z',
links: {
npm: 'https://www.npmjs.com/package/%40evocateur%2Flibnpmaccess',
homepage: 'https://npmjs.com/package/@evocateur/libnpmaccess',
@@ -63,7 +64,7 @@ module.exports = [
scope: 'evocateur',
version: '1.2.2',
description: 'Programmatic API for the bits behind npm publish and unpublish',
date: new Date('2019-07-16T19:40:40.850Z'),
date: '2019-07-16T19:40:40.850Z',
links: {
npm: 'https://www.npmjs.com/package/%40evocateur%2Flibnpmpublish',
homepage: 'https://npmjs.com/package/@evocateur/libnpmpublish',
@@ -80,7 +81,7 @@ module.exports = [
version: '2.0.1',
description: 'Programmatic api for `npm org` commands',
keywords: ['libnpm', 'npm', 'package manager', 'api', 'orgs', 'teams'],
date: new Date('2020-11-03T19:21:57.757Z'),
date: '2020-11-03T19:21:57.757Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmorg',
homepage: 'https://npmjs.com/package/libnpmorg',
@@ -102,7 +103,7 @@ module.exports = [
version: '3.1.0',
description: 'Programmatic API for searching in npm and compatible registries.',
keywords: ['npm', 'search', 'api', 'libnpm'],
date: new Date('2020-12-08T23:54:18.374Z'),
date: '2020-12-08T23:54:18.374Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmsearch',
homepage: 'https://npmjs.com/package/libnpmsearch',
@@ -123,7 +124,7 @@ module.exports = [
scope: 'unscoped',
version: '2.0.2',
description: 'npm Team management APIs',
date: new Date('2020-11-03T19:24:42.380Z'),
date: '2020-11-03T19:24:42.380Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmteam',
homepage: 'https://npmjs.com/package/libnpmteam',
@@ -145,7 +146,7 @@ module.exports = [
version: '6.0.1',
description: 'programmatic API for managing npm registry hooks',
keywords: ['npm', 'hooks', 'registry', 'npm api'],
date: new Date('2020-11-03T19:20:45.818Z'),
date: '2020-11-03T19:20:45.818Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmhook',
homepage: 'https://github.com/npm/libnpmhook#readme',
@@ -166,7 +167,7 @@ module.exports = [
scope: 'unscoped',
version: '4.0.0',
description: 'Programmatic API for the bits behind npm publish and unpublish',
date: new Date('2020-11-03T19:13:43.780Z'),
date: '2020-11-03T19:13:43.780Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmpublish',
homepage: 'https://npmjs.com/package/libnpmpublish',
@@ -193,7 +194,7 @@ module.exports = [
'git', 'fund',
'gitfund',
],
date: new Date('2020-12-08T23:22:00.213Z'),
date: '2020-12-08T23:22:00.213Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmfund',
homepage: 'https://github.com/npm/libnpmfund#readme',
@@ -222,7 +223,7 @@ module.exports = [
'workspaces',
'map-workspaces',
],
date: new Date('2020-09-30T15:16:29.017Z'),
date: '2020-09-30T15:16:29.017Z',
links: {
npm: 'https://www.npmjs.com/package/%40npmcli%2Fmap-workspaces',
homepage: 'https://github.com/npm/map-workspaces#readme',
@@ -243,7 +244,7 @@ module.exports = [
scope: 'unscoped',
version: '1.0.7',
description: "library to do the things that 'npm version' does",
date: new Date('2020-11-04T00:21:41.069Z'),
date: '2020-11-04T00:21:41.069Z',
links: {
npm: 'https://www.npmjs.com/package/libnpmversion',
homepage: 'https://github.com/npm/libnpmversion#readme',
@@ -269,7 +270,7 @@ module.exports = [
scope: 'types',
version: '2.0.1',
description: 'TypeScript definitions for libnpmsearch',
date: new Date('2019-09-26T22:24:28.713Z'),
date: '2019-09-26T22:24:28.713Z',
links: { npm: 'https://www.npmjs.com/package/%40types%2Flibnpmsearch' },
publisher: { username: 'types', email: 'ts-npm-types@microsoft.com' },
maintainers: [{ username: 'types', email: 'ts-npm-types@microsoft.com' }],
13 changes: 13 additions & 0 deletions test/fixtures/mock-registry.js
Original file line number Diff line number Diff line change
@@ -46,6 +46,19 @@ class MockRegistry {
this.#nock = nock
}

search ({ responseCode = 200, results = [], error }) {
// the flags, score, and searchScore parts of the response are never used
// by npm, only package is used
const response = results.map(p => ({ package: p }))
this.nock = this.nock.get('/-/v1/search').query(true)
if (error) {
this.nock = this.nock.replyWithError(error)
} else {
this.nock = this.nock.reply(responseCode, { objects: response })
}
return this.nock
}

whoami ({ username, body, responseCode = 200, times = 1 }) {
if (username) {
this.nock = this.nock.get('/-/whoami').times(times).reply(responseCode, { username })
302 changes: 133 additions & 169 deletions test/lib/commands/search.js
Original file line number Diff line number Diff line change
@@ -1,169 +1,92 @@
const t = require('tap')
const Minipass = require('minipass')
const { fake: mockNpm } = require('../../fixtures/mock-npm')
const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
const MockRegistry = require('../../fixtures/mock-registry.js')
const libnpmsearchResultFixture =
require('../../fixtures/libnpmsearch-stream-result.js')

let result = ''
const flatOptions = {
search: {
exclude: null,
limit: 20,
opts: '',
},
}
const config = {
json: false,
parseable: false,
}
const npm = mockNpm({
config,
flatOptions: { ...flatOptions },
output: (...msg) => {
result += msg.join('\n')
},
})
const npmlog = {
silly () {},
clearProgress () {},
}
const libnpmsearch = {
stream () {},
}
const mocks = {
npmlog,
libnpmsearch,
}

t.afterEach(() => {
result = ''
config.json = false
config.parseable = false
npm.flatOptions = { ...flatOptions }
})

const Search = t.mock('../../../lib/commands/search.js', mocks)
const search = new Search(npm)

t.test('no args', async t => {
const { npm } = await loadMockNpm(t)
await t.rejects(
search.exec([]),
npm.exec('search', []),
/search must be called with arguments/,
'should throw usage instructions'
)
})

t.test('search <name>', async t => {
const src = new Minipass()
src.objectMode = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
t.test('search <name> text', async t => {
const { npm, joinedOutput } = await loadMockNpm(t)
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

for (const i of libnpmsearchResultFixture) {
src.write(i)
}

src.end()

await search.exec(['libnpm'])
t.matchSnapshot(result, 'should have expected search results')
registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'should have expected search results')
})

t.test('search <name> --json', async t => {
const src = new Minipass()
src.objectMode = true

npm.flatOptions.json = true
config.json = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

for (const i of libnpmsearchResultFixture) {
src.write(i)
}
registry.search({ results: libnpmsearchResultFixture })

src.end()
await search.exec(['libnpm'])

const parsedResult = JSON.parse(result)
parsedResult.forEach((entry) => {
entry.date = new Date(entry.date)
})
await npm.exec('search', ['libnpm'])

t.same(
parsedResult,
JSON.parse(joinedOutput()),
libnpmsearchResultFixture,
'should have expected search results as json'
)
})

config.json = false
t.test('search <name> --parseable', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { parseable: true } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'should have expected search results as parseable')
})

t.test('search <invalid-module> --json', async t => {
const src = new Minipass()
src.objectMode = true

npm.flatOptions.json = true
config.json = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
t.test('search <name> --color', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

src.end()
await search.exec(['foo'])
registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'should have expected search results with color')
})

t.equal(result, '\n[]\n', 'should have expected empty square brackets')
t.test('search /<name>/--color', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

config.json = false
registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['/libnpm/'])
t.matchSnapshot(joinedOutput(), 'should have expected search results with color')
})

t.test('search <name> --searchexclude --searchopts', async t => {
npm.flatOptions.search = {
...flatOptions.search,
exclude: '',
}

const src = new Minipass()
src.objectMode = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
t.test('search <name>', async t => {
const { npm, joinedOutput } = await loadMockNpm(t)
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

src.write({
registry.search({ results: [{
name: 'foo',
scope: 'unscoped',
version: '1.0.0',
@@ -175,8 +98,7 @@ t.test('search <name> --searchexclude --searchopts', async t => {
maintainers: [
{ username: 'foo', email: 'foo@npmjs.com' },
],
})
src.write({
}, {
name: 'libnpmversion',
scope: 'unscoped',
version: '1.0.0',
@@ -188,58 +110,100 @@ t.test('search <name> --searchexclude --searchopts', async t => {
maintainers: [
{ username: 'foo', email: 'foo@npmjs.com' },
],
})
}] })

src.end()
await search.exec(['foo'])
await npm.exec('search', ['foo'])

t.matchSnapshot(result, 'should have filtered expected search results')
t.matchSnapshot(joinedOutput(), 'should have filtered expected search results')
})

t.test('empty search results', async t => {
const src = new Minipass()
src.objectMode = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
const { npm, joinedOutput } = await loadMockNpm(t)
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

src.end()
await search.exec(['foo'])
registry.search({ results: [] })
await npm.exec('search', ['foo'])

t.matchSnapshot(result, 'should have expected search results')
t.matchSnapshot(joinedOutput(), 'should have expected search results')
})

t.test('search api response error', async t => {
const src = new Minipass()
src.objectMode = true
const libnpmsearch = {
stream () {
return src
},
}

const Search = t.mock('../../../lib/commands/search.js', {
...mocks,
libnpmsearch,
t.test('empty search results --json', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})
const search = new Search(npm)

setImmediate(() => {
src.emit('error', new Error('ERR'))
src.end()
registry.search({ results: [] })

await npm.exec('search', ['foo'])
t.equal(joinedOutput(), '\n[]\n', 'should have expected empty square brackets')
})

t.test('search api response error', async t => {
const { npm } = await loadMockNpm(t)

const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ error: 'ERR' })

await t.rejects(
search.exec(['foo']),
npm.exec('search', ['foo']),
/ERR/,
'should throw response error'
)
})

t.test('search exclude string', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: 'libnpmversion' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion')
})

t.test('search exclude username with upper case letters', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: 'NLF' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'results should not have nlf')
})

t.test('search exclude regex', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version/' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion')
})

t.test('search exclude forward slash', async t => {
const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version' } })
const registry = new MockRegistry({
tap: t,
registry: npm.config.get('registry'),
})

registry.search({ results: libnpmsearchResultFixture })
await npm.exec('search', ['libnpm'])
t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion')
})
457 changes: 183 additions & 274 deletions test/lib/commands/view.js

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions test/lib/utils/config/definitions.js
Original file line number Diff line number Diff line change
@@ -457,6 +457,13 @@ t.test('retry options', t => {
})

t.test('search options', t => {
const vals = {
description: 'test description',
exclude: 'test search exclude',
limit: 99,
staleneess: 99,

}
const obj = {}
// <config>: flat.search[<option>]
const mapping = {
@@ -469,9 +476,9 @@ t.test('search options', t => {
for (const [config, option] of Object.entries(mapping)) {
const msg = `${config} -> search.${option}`
const flat = {}
obj[config] = 99
obj[config] = vals[option]
definitions[config].flatten(config, obj, flat)
t.strictSame(flat, { search: { limit: 20, [option]: 99 } }, msg)
t.strictSame(flat, { search: { limit: 20, [option]: vals[option] } }, msg)
delete obj[config]
}

30 changes: 0 additions & 30 deletions test/lib/utils/file-exists.js

This file was deleted.

0 comments on commit 48d2db6

Please sign in to comment.