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
diff options
context:
space:
mode:
authorLuke Karrys <luke@lukekarrys.com>2022-04-08 18:24:56 +0300
committerNathan Fritz <fritzy@github.com>2022-04-14 00:20:48 +0300
commit672fce84b25ecbe58d311acfae6c43e5ca2d778d (patch)
tree39e8ac90263f4386284e8d93ef2bbe7f30a9f32a /smoke-tests
parent3f7fe17d1ea743b3ce1f27b9156e9fa0e358a7df (diff)
chore: refactor smoke-tests
Diffstat (limited to 'smoke-tests')
-rw-r--r--smoke-tests/.eslintrc.js15
-rw-r--r--smoke-tests/.gitignore21
-rw-r--r--smoke-tests/package.json49
-rw-r--r--smoke-tests/server.js282
-rw-r--r--smoke-tests/tap-snapshots/test/index.js.test.cjs784
-rw-r--r--smoke-tests/test/fixtures/abbrev.json (renamed from smoke-tests/content/abbrev.json)0
-rw-r--r--smoke-tests/test/fixtures/abbrev.min.json (renamed from smoke-tests/content/abbrev.min.json)0
-rw-r--r--smoke-tests/test/fixtures/abbrev/-/abbrev-1.0.4.tgz (renamed from smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz)bin2295 -> 2295 bytes
-rw-r--r--smoke-tests/test/fixtures/abbrev/-/abbrev-1.1.1.tgz (renamed from smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz)bin2301 -> 2301 bytes
-rw-r--r--smoke-tests/test/fixtures/promise-all-reject-late.json (renamed from smoke-tests/content/promise-all-reject-late.json)0
-rw-r--r--smoke-tests/test/fixtures/promise-all-reject-late.min.json (renamed from smoke-tests/content/promise-all-reject-late.min.json)0
-rw-r--r--smoke-tests/test/fixtures/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz (renamed from smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz)bin30838 -> 30838 bytes
-rw-r--r--smoke-tests/test/fixtures/server.js49
-rw-r--r--smoke-tests/test/index.js (renamed from smoke-tests/index.js)249
14 files changed, 1047 insertions, 402 deletions
diff --git a/smoke-tests/.eslintrc.js b/smoke-tests/.eslintrc.js
new file mode 100644
index 000000000..0e8ad0071
--- /dev/null
+++ b/smoke-tests/.eslintrc.js
@@ -0,0 +1,15 @@
+/* This file is automatically added by @npmcli/template-oss. Do not edit. */
+
+const { readdirSync: readdir } = require('fs')
+
+const localConfigs = readdir(__dirname)
+ .filter((file) => file.startsWith('.eslintrc.local.'))
+ .map((file) => `./${file}`)
+
+module.exports = {
+ root: true,
+ extends: [
+ '@npmcli',
+ ...localConfigs,
+ ],
+}
diff --git a/smoke-tests/.gitignore b/smoke-tests/.gitignore
new file mode 100644
index 000000000..617e50ca0
--- /dev/null
+++ b/smoke-tests/.gitignore
@@ -0,0 +1,21 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+# ignore everything in the root
+/*
+
+# keep these
+!/.eslintrc.local.*
+!**/.gitignore
+!/docs/
+!/tap-snapshots/
+!/test/
+!/map.js
+!/scripts/
+!/README*
+!/LICENSE*
+!/CHANGELOG*
+!/.eslintrc.js
+!/.gitignore
+!/bin/
+!/lib/
+!/package.json
diff --git a/smoke-tests/package.json b/smoke-tests/package.json
new file mode 100644
index 000000000..f8d1ffd0b
--- /dev/null
+++ b/smoke-tests/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "smoke-tests",
+ "description": "The npm cli smoke tests",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "lint": "eslint \"**/*.js\"",
+ "postlint": "template-oss-check",
+ "template-oss-apply": "template-oss-apply --force",
+ "lintfix": "npm run lint -- --fix",
+ "preversion": "npm test",
+ "postversion": "git push origin --follow-tags",
+ "snap": "tap",
+ "test": "tap",
+ "posttest": "npm run lint"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/npm/cli.git",
+ "directory": "smoke-tests"
+ },
+ "devDependencies": {
+ "@npmcli/eslint-config": "^3.0.1",
+ "@npmcli/promise-spawn": "^3.0.0",
+ "@npmcli/template-oss": "3.3.2",
+ "minify-registry-metadata": "^2.2.0",
+ "rimraf": "^3.0.2",
+ "tap": "^16.0.1",
+ "which": "^2.0.2"
+ },
+ "author": "GitHub Inc.",
+ "license": "ISC",
+ "templateOSS": {
+ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
+ "version": "3.3.2",
+ "workspaceRepo": false
+ },
+ "tap": {
+ "no-coverage": true,
+ "files": "test/index.js"
+ },
+ "files": [
+ "bin/",
+ "lib/"
+ ],
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+}
diff --git a/smoke-tests/server.js b/smoke-tests/server.js
deleted file mode 100644
index 31ffebb2a..000000000
--- a/smoke-tests/server.js
+++ /dev/null
@@ -1,282 +0,0 @@
-/* istanbul ignore file */
-const { join, dirname, basename } = require('path')
-const { existsSync, readFileSync, writeFileSync } = require('fs')
-const PORT = 12345 + (+process.env.TAP_CHILD_ID || 0)
-const http = require('http')
-const https = require('https')
-
-const mkdirp = require('mkdirp')
-const doProxy = process.env.ARBORIST_TEST_PROXY
-const missing = /\/@isaacs(\/|%2[fF])(this-does-not-exist-at-all|testing-missing-tgz\/-\/)/
-const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
-const { gzipSync, unzipSync } = require('zlib')
-
-let advisoryBulkResponse = null
-let failAdvisoryBulk = false
-let auditResponse = null
-let failAudit = false
-const startServer = () => new Promise((res, rej) => {
- const server = exports.server = http.createServer((req, res) => {
- res.setHeader('connection', 'close')
-
- if (req.url === '/-/npm/v1/security/advisories/bulk') {
- const body = []
- req.on('data', c => body.push(c))
- req.on('end', () => {
- res.setHeader('connection', 'close')
- if (failAdvisoryBulk) {
- res.statusCode = 503
- return res.end('no advisory bulk for you')
- }
- if (!advisoryBulkResponse) {
- if (auditResponse && !failAudit) {
- // simulate what the registry does when quick audits are allowed,
- // but advisory bulk requests are not
- res.statusCode = 405
- return res.end(JSON.stringify({
- code: 'MethodNotAllowedError',
- message: 'POST is not allowed',
- }))
- } else {
- res.statusCode = 404
- return res.end('not found')
- }
- }
- if (doProxy && !existsSync(advisoryBulkResponse)) {
- // hit the main registry, then fall back to staging for now
- // XXX: remove this when bulk advisory endpoint pushed to production!
- const opts = {
- host: 'registry.npmjs.org',
- method: req.method,
- path: req.url,
- headers: {
- ...req.headers,
- accept: '*',
- host: 'registry.npmjs.org',
- connection: 'close',
- 'if-none-match': '',
- },
- }
- const handleUpstream = upstream => {
- res.statusCode = upstream.statusCode
- if (upstream.statusCode >= 300 || upstream.statusCode < 200) {
- console.error('UPSTREAM ERROR', upstream.statusCode)
- return upstream.pipe(res)
- }
- res.setHeader('content-encoding', upstream.headers['content-encoding'])
- const file = advisoryBulkResponse
- console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`)
- mkdirp.sync(dirname(file))
- const data = []
- upstream.on('end', () => {
- const out = Buffer.concat(data)
- const obj = JSON.parse(unzipSync(out).toString())
- writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n')
- res.end(out)
- })
- upstream.on('data', c => data.push(c))
- }
- return https.request(opts).on('response', upstream => {
- if (upstream.statusCode !== 200) {
- console.error('ATTEMPTING TO PROXY FROM STAGING')
- console.error('NOTE: THIS WILL FAIL WHEN NOT ON VPN!')
- opts.host = 'security-microservice-3-west.npm.red'
- opts.headers.host = opts.host
- opts.path = '/v1/advisories/bulk'
- https.request(opts)
- .on('response', upstream => handleUpstream(upstream))
- .end(Buffer.concat(body))
- } else {
- handleUpstream(upstream)
- }
- }).end(Buffer.concat(body))
- } else {
- res.setHeader('content-encoding', 'gzip')
- res.end(gzipSync(readFileSync(advisoryBulkResponse)))
- }
- })
- return
- } else if (req.url === '/-/npm/v1/security/audits/quick') {
- const body = []
- req.on('data', c => body.push(c))
- req.on('end', () => {
- res.setHeader('connection', 'close')
- if (failAudit) {
- res.statusCode = 503
- return res.end('no audit for you')
- }
- if (!auditResponse) {
- res.statusCode = 404
- return res.end('not found')
- }
- if (doProxy && !existsSync(auditResponse)) {
- return https.request({
- host: 'registry.npmjs.org',
- method: req.method,
- path: req.url,
- headers: {
- ...req.headers,
- accept: '*',
- host: 'registry.npmjs.org',
- connection: 'close',
- 'if-none-match': '',
- },
- }).on('response', upstream => {
- res.statusCode = upstream.statusCode
- if (upstream.statusCode >= 300 || upstream.statusCode < 200) {
- console.error('UPSTREAM ERROR', upstream.statusCode)
- // don't save if it's not a valid response
- return upstream.pipe(res)
- }
- res.setHeader('content-encoding', upstream.headers['content-encoding'])
- const file = auditResponse
- console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`)
- mkdirp.sync(dirname(file))
- const data = []
- upstream.on('end', () => {
- const out = Buffer.concat(data)
- // make it a bit prettier to read later
- const obj = JSON.parse(unzipSync(out).toString())
- writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n')
- res.end(out)
- })
- upstream.on('data', c => data.push(c))
- }).end(Buffer.concat(body))
- } else {
- res.setHeader('content-encoding', 'gzip')
- res.end(gzipSync(readFileSync(auditResponse)))
- }
- })
- return
- }
-
- const f = join(__dirname, 'content', join('/', req.url.replace(/@/, '').replace(/%2f/i, '/')))
- // a magic package that causes us to return an error that will be logged
- if (basename(f) === 'fail_reflect_user_agent') {
- res.setHeader('npm-notice', req.headers['user-agent'])
- res.writeHead(404)
- return res.end()
- }
- const isCorgi = req.headers.accept.includes('application/vnd.npm.install-v1+json')
- const file = f + (
- isCorgi && existsSync(`${f}.min.json`) ? '.min.json'
- : existsSync(`${f}.json`) ? '.json'
- : existsSync(`${f}/index.json`) ? 'index.json'
- : ''
- )
-
- try {
- const body = readFileSync(file)
- res.setHeader('content-length', body.length)
- res.setHeader('content-type', /\.min\.json$/.test(file) ? corgiDoc
- : /\.json$/.test(file) ? 'application/json'
- : 'application/octet-stream')
- res.end(body)
- } catch (er) {
- // testing things going missing from the registry somehow
- if (missing.test(req.url)) {
- res.statusCode = 404
- res.end('{"error": "not found"}')
- return
- }
-
- if (doProxy) {
- return https.get({
- host: 'registry.npmjs.org',
- path: req.url,
- headers: {
- ...req.headers,
- accept: '*',
- 'accept-encoding': 'identity',
- host: 'registry.npmjs.org',
- connection: 'close',
- 'if-none-match': '',
- },
- }).on('response', upstream => {
- const errorStatus =
- upstream.statusCode >= 300 || upstream.statusCode < 200
-
- if (errorStatus) {
- console.error('UPSTREAM ERROR', upstream.statusCode)
- }
-
- const ct = upstream.headers['content-type']
- const isJson = ct.includes('application/json')
- const file = isJson ? f + '.json' : f
- console.error('PROXY', `${req.url} -> ${file} ${ct}`)
- mkdirp.sync(dirname(file))
- const data = []
- res.statusCode = upstream.statusCode
- res.setHeader('content-type', ct)
- upstream.on('end', () => {
- console.error('ENDING', req.url)
- const out = Buffer.concat(data)
- if (!errorStatus) {
- if (isJson) {
- const obj = JSON.parse(out.toString())
- writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n')
- const mrm = require('minify-registry-metadata')
- const minFile = file.replace(/\.json$/, '.min.json')
- writeFileSync(minFile, JSON.stringify(mrm(obj), 0, 2) + '\n')
- console.error('WROTE JSONS', [file, minFile])
- } else {
- writeFileSync(file, out)
- }
- }
- res.end(out)
- })
- upstream.on('data', c => data.push(c))
- }).end()
- }
-
- res.statusCode = er.code === 'ENOENT' ? 404 : 500
- if (res.method === 'GET') {
- console.error(er)
- }
- res.setHeader('content-type', 'text/plain')
- res.end(er.stack)
- }
- })
- server.listen(PORT, res)
-})
-
-exports.auditResponse = value => {
- if (auditResponse && auditResponse !== value) {
- throw new Error('setting audit response, but already set\n' +
- '(did you forget to call the returned function on teardown?)')
- }
- auditResponse = value
- return () => auditResponse = null
-}
-exports.failAudit = () => {
- failAudit = true
- return () => failAudit = false
-}
-
-exports.advisoryBulkResponse = value => {
- if (advisoryBulkResponse && advisoryBulkResponse !== value) {
- throw new Error('setting advisory bulk response, but already set\n' +
- '(did you forget to call the returned function on teardown?)')
- }
- advisoryBulkResponse = value
- return () => advisoryBulkResponse = null
-}
-exports.failAdvisoryBulk = () => {
- failAdvisoryBulk = true
- return () => failAdvisoryBulk = false
-}
-
-exports.registry = `http://localhost:${PORT}/`
-
-exports.start = startServer
-exports.stop = () => exports.server.close()
-
-if (require.main === module) {
- startServer().then(() => {
- console.log(`Mock registry live at:
- ${exports.registry}
-Press ^D to close gracefully.`)
- })
- process.openStdin()
- process.stdin.on('end', () => exports.stop())
-}
diff --git a/smoke-tests/tap-snapshots/test/index.js.test.cjs b/smoke-tests/tap-snapshots/test/index.js.test.cjs
new file mode 100644
index 000000000..486849d6c
--- /dev/null
+++ b/smoke-tests/tap-snapshots/test/index.js.test.cjs
@@ -0,0 +1,784 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/index.js TAP npm (no args) > should have expected no args output 1`] = `
+npm <command>
+
+Usage:
+
+npm install install all the dependencies in your project
+npm install <foo> add the <foo> dependency to your project
+npm test run this project's tests
+npm run <foo> run the script named <foo>
+npm <command> -h quick help on <command>
+npm -l display usage info for all commands
+npm help <term> search for help on <term>
+npm help npm more involved overview
+
+All commands:
+
+ access, adduser, audit, bin, bugs, cache, ci, completion,
+ config, dedupe, deprecate, diff, dist-tag, docs, doctor,
+ edit, exec, explain, explore, find-dupes, fund, get, help,
+ hook, init, install, install-ci-test, install-test, link,
+ ll, login, logout, ls, org, outdated, owner, pack, ping,
+ pkg, prefix, profile, prune, publish, rebuild, repo,
+ restart, root, run-script, search, set, set-script,
+ shrinkwrap, star, stars, start, stop, team, test, token,
+ uninstall, unpublish, unstar, update, version, view, whoami
+
+Specify configs in the ini-formatted file:
+ {CWD}/smoke-tests/test/tap-testdir-index/.npmrc
+or on the command line via: npm <command> --key=value
+
+More configuration info: npm help config
+Configuration fields: npm help 7 config
+
+npm {CWD}
+
+`
+
+exports[`test/index.js TAP npm ci > should throw mismatch deps in lock file error 1`] = `
+npm ERR! \`npm ci\` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with \`npm install\` before continuing.
+npm ERR!
+npm ERR! Invalid: lock file's abbrev@1.0.4 does not satisfy abbrev@1.1.1
+npm ERR!
+
+npm ERR! A complete log of this run can be found in:
+
+
+`
+
+exports[`test/index.js TAP npm diff > should have expected diff output 1`] = `
+diff --git a/package.json b/package.json
+index v1.0.4..v1.1.1 100644
+--- a/package.json
++++ b/package.json
+@@ -1,15 +1,21 @@
+ {
+ "name": "abbrev",
+- "version": "1.0.4",
++ "version": "1.1.1",
+ "description": "Like ruby's abbrev module, but in js",
+ "author": "Isaac Z. Schlueter <i@izs.me>",
+- "main": "./lib/abbrev.js",
++ "main": "abbrev.js",
+ "scripts": {
+- "test": "node lib/abbrev.js"
++ "test": "tap test.js --100",
++ "preversion": "npm test",
++ "postversion": "npm publish",
++ "postpublish": "git push origin --all; git push origin --tags"
+ },
+ "repository": "http://github.com/isaacs/abbrev-js",
+- "license": {
+- "type": "MIT",
+- "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE"
+- }
++ "license": "ISC",
++ "devDependencies": {
++ "tap": "^10.1"
++ },
++ "files": [
++ "abbrev.js"
++ ]
+ }
+diff --git a/LICENSE b/LICENSE
+index v1.0.4..v1.1.1 100644
+--- a/LICENSE
++++ b/LICENSE
+@@ -1,4 +1,27 @@
+-Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
++This software is dual-licensed under the ISC and MIT licenses.
++You may use this software under EITHER of the following licenses.
++
++----------
++
++The ISC License
++
++Copyright (c) Isaac Z. Schlueter and Contributors
++
++Permission to use, copy, modify, and/or distribute this software for any
++purpose with or without fee is hereby granted, provided that the above
++copyright notice and this permission notice appear in all copies.
++
++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++----------
++
++Copyright Isaac Z. Schlueter and Contributors
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+diff --git a/lib/abbrev.js b/lib/abbrev.js
+deleted file mode 100644
+index v1.0.4..v1.1.1
+--- a/lib/abbrev.js
++++ b/lib/abbrev.js
+@@ -1,111 +0,0 @@
+-
+-module.exports = exports = abbrev.abbrev = abbrev
+-
+-abbrev.monkeyPatch = monkeyPatch
+-
+-function monkeyPatch () {
+- Object.defineProperty(Array.prototype, 'abbrev', {
+- value: function () { return abbrev(this) },
+- enumerable: false, configurable: true, writable: true
+- })
+-
+- Object.defineProperty(Object.prototype, 'abbrev', {
+- value: function () { return abbrev(Object.keys(this)) },
+- enumerable: false, configurable: true, writable: true
+- })
+-}
+-
+-function abbrev (list) {
+- if (arguments.length !== 1 || !Array.isArray(list)) {
+- list = Array.prototype.slice.call(arguments, 0)
+- }
+- for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
+- args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
+- }
+-
+- // sort them lexicographically, so that they're next to their nearest kin
+- args = args.sort(lexSort)
+-
+- // walk through each, seeing how much it has in common with the next and previous
+- var abbrevs = {}
+- , prev = ""
+- for (var i = 0, l = args.length ; i < l ; i ++) {
+- var current = args[i]
+- , next = args[i + 1] || ""
+- , nextMatches = true
+- , prevMatches = true
+- if (current === next) continue
+- for (var j = 0, cl = current.length ; j < cl ; j ++) {
+- var curChar = current.charAt(j)
+- nextMatches = nextMatches && curChar === next.charAt(j)
+- prevMatches = prevMatches && curChar === prev.charAt(j)
+- if (!nextMatches && !prevMatches) {
+- j ++
+- break
+- }
+- }
+- prev = current
+- if (j === cl) {
+- abbrevs[current] = current
+- continue
+- }
+- for (var a = current.substr(0, j) ; j <= cl ; j ++) {
+- abbrevs[a] = current
+- a += current.charAt(j)
+- }
+- }
+- return abbrevs
+-}
+-
+-function lexSort (a, b) {
+- return a === b ? 0 : a > b ? 1 : -1
+-}
+-
+-
+-// tests
+-if (module === require.main) {
+-
+-var assert = require("assert")
+-var util = require("util")
+-
+-console.log("running tests")
+-function test (list, expect) {
+- var actual = abbrev(list)
+- assert.deepEqual(actual, expect,
+- "abbrev("+util.inspect(list)+") === " + util.inspect(expect) + "/n"+
+- "actual: "+util.inspect(actual))
+- actual = abbrev.apply(exports, list)
+- assert.deepEqual(abbrev.apply(exports, list), expect,
+- "abbrev("+list.map(JSON.stringify).join(",")+") === " + util.inspect(expect) + "/n"+
+- "actual: "+util.inspect(actual))
+-}
+-
+-test([ "ruby", "ruby", "rules", "rules", "rules" ],
+-{ rub: 'ruby'
+-, ruby: 'ruby'
+-, rul: 'rules'
+-, rule: 'rules'
+-, rules: 'rules'
+-})
+-test(["fool", "foom", "pool", "pope"],
+-{ fool: 'fool'
+-, foom: 'foom'
+-, poo: 'pool'
+-, pool: 'pool'
+-, pop: 'pope'
+-, pope: 'pope'
+-})
+-test(["a", "ab", "abc", "abcd", "abcde", "acde"],
+-{ a: 'a'
+-, ab: 'ab'
+-, abc: 'abc'
+-, abcd: 'abcd'
+-, abcde: 'abcde'
+-, ac: 'acde'
+-, acd: 'acde'
+-, acde: 'acde'
+-})
+-
+-console.log("pass")
+-
+-}
+/ No newline at end of file
+diff --git a/abbrev.js b/abbrev.js
+new file mode 100644
+index v1.0.4..v1.1.1
+--- a/abbrev.js
++++ b/abbrev.js
+@@ -0,0 +1,61 @@
++module.exports = exports = abbrev.abbrev = abbrev
++
++abbrev.monkeyPatch = monkeyPatch
++
++function monkeyPatch () {
++ Object.defineProperty(Array.prototype, 'abbrev', {
++ value: function () { return abbrev(this) },
++ enumerable: false, configurable: true, writable: true
++ })
++
++ Object.defineProperty(Object.prototype, 'abbrev', {
++ value: function () { return abbrev(Object.keys(this)) },
++ enumerable: false, configurable: true, writable: true
++ })
++}
++
++function abbrev (list) {
++ if (arguments.length !== 1 || !Array.isArray(list)) {
++ list = Array.prototype.slice.call(arguments, 0)
++ }
++ for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
++ args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
++ }
++
++ // sort them lexicographically, so that they're next to their nearest kin
++ args = args.sort(lexSort)
++
++ // walk through each, seeing how much it has in common with the next and previous
++ var abbrevs = {}
++ , prev = ""
++ for (var i = 0, l = args.length ; i < l ; i ++) {
++ var current = args[i]
++ , next = args[i + 1] || ""
++ , nextMatches = true
++ , prevMatches = true
++ if (current === next) continue
++ for (var j = 0, cl = current.length ; j < cl ; j ++) {
++ var curChar = current.charAt(j)
++ nextMatches = nextMatches && curChar === next.charAt(j)
++ prevMatches = prevMatches && curChar === prev.charAt(j)
++ if (!nextMatches && !prevMatches) {
++ j ++
++ break
++ }
++ }
++ prev = current
++ if (j === cl) {
++ abbrevs[current] = current
++ continue
++ }
++ for (var a = current.substr(0, j) ; j <= cl ; j ++) {
++ abbrevs[a] = current
++ a += current.charAt(j)
++ }
++ }
++ return abbrevs
++}
++
++function lexSort (a, b) {
++ return a === b ? 0 : a > b ? 1 : -1
++}
+
+`
+
+exports[`test/index.js TAP npm explain > should have expected explain output 1`] = `
+abbrev@1.0.4
+node_modules/abbrev
+ abbrev@"^1.0.4" from the root project
+
+`
+
+exports[`test/index.js TAP npm fund > should have expected fund output 1`] = `
+project@1.0.0
+\`-- https://github.com/sponsors/isaacs
+ \`-- promise-all-reject-late@1.0.1
+
+
+`
+
+exports[`test/index.js TAP npm init > should have successful npm init result 1`] = `
+Wrote to {CWD}/smoke-tests/test/tap-testdir-index/project/package.json:
+
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
+}
+
+
+
+`
+
+exports[`test/index.js TAP npm install dev dep > should have expected dev dep added lockfile result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "project",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "devDependencies": {
+ "promise-all-reject-late": "^1.0.1"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
+ "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
+ },
+ "node_modules/promise-all-reject-late": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+ "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ }
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
+ "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
+ },
+ "promise-all-reject-late": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+ "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+ "dev": true
+ }
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm install dev dep > should have expected dev dep added package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "devDependencies": {
+ "promise-all-reject-late": "^1.0.1"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm install dev dep > should have expected dev dep added reify output 1`] = `
+
+added 1 package
+
+1 package is looking for funding
+ run \`npm fund\` for details
+
+`
+
+exports[`test/index.js TAP npm install prodDep@version > should have expected install reify output 1`] = `
+
+added 1 package
+
+`
+
+exports[`test/index.js TAP npm install prodDep@version > should have expected lockfile result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "project",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
+ "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
+ }
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
+ "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
+ }
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm install prodDep@version > should have expected package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm ls > should have expected ls output 1`] = `
+project@1.0.0 {CWD}/smoke-tests/test/tap-testdir-index/project
++-- abbrev@1.0.4
+\`-- promise-all-reject-late@1.0.1
+
+
+`
+
+exports[`test/index.js TAP npm outdated > should have expected outdated output 1`] = `
+Package Current Wanted Latest Location Depended by
+abbrev 1.0.4 1.1.1 1.1.1 node_modules/abbrev project
+
+`
+
+exports[`test/index.js TAP npm pkg > should have expected npm pkg delete modified package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm pkg > should have expected npm pkg set modified package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "tap": {
+ "test-env": [
+ "LC_ALL=sk"
+ ]
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm pkg > should have expected pkg delete output 1`] = `
+
+`
+
+exports[`test/index.js TAP npm pkg > should have expected pkg get output 1`] = `
+"ISC"
+
+`
+
+exports[`test/index.js TAP npm pkg > should have expected pkg set output 1`] = `
+
+`
+
+exports[`test/index.js TAP npm pkg > should print package.json contents 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "ma",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "tap": {
+ "test-env": [
+ "LC_ALL=sk"
+ ]
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm prefix > should have expected prefix output 1`] = `
+{CWD}/smoke-tests/test/tap-testdir-index/project
+
+`
+
+exports[`test/index.js TAP npm run-script > should have expected run-script output 1`] = `
+
+> project@1.0.0 hello
+> echo Hello
+
+Hello
+
+`
+
+exports[`test/index.js TAP npm set-script > should have expected script added package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "devDependencies": {
+ "promise-all-reject-late": "^1.0.1"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm set-script > should have expected set-script output 1`] = `
+
+`
+
+exports[`test/index.js TAP npm uninstall > should have expected uninstall lockfile result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "project",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ }
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ }
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm uninstall > should have expected uninstall package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm uninstall > should have expected uninstall reify output 1`] = `
+
+removed 1 package
+
+`
+
+exports[`test/index.js TAP npm update dep > should have expected update lockfile result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "project",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "devDependencies": {
+ "promise-all-reject-late": "^1.0.1"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "node_modules/promise-all-reject-late": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+ "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ }
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "promise-all-reject-late": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+ "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+ "dev": true
+ }
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm update dep > should have expected update package.json result 1`] = `
+{
+ "name": "project",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo /"Error: no test specified/" && exit 1",
+ "hello": "echo Hello"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^1.0.4"
+ },
+ "devDependencies": {
+ "promise-all-reject-late": "^1.0.1"
+ }
+}
+
+`
+
+exports[`test/index.js TAP npm update dep > should have expected update reify output 1`] = `
+
+changed 1 package
+
+1 package is looking for funding
+ run \`npm fund\` for details
+
+`
+
+exports[`test/index.js TAP npm view > should have expected view output 1`] = `
+
+abbrev@1.0.4 | MIT | deps: none | versions: 8
+Like ruby's abbrev module, but in js
+https://github.com/isaacs/abbrev-js#readme
+
+dist
+.tarball: https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz
+.shasum: bd55ae5e413ba1722ee4caba1f6ea10414a59ecd
+
+maintainers:
+- nlf <quitlahok@gmail.com>
+- ruyadorno <ruyadorno@hotmail.com>
+- darcyclarke <darcy@darcyclarke.me>
+- adam_baldwin <evilpacket@gmail.com>
+- isaacs <i@izs.me>
+
+dist-tags:
+latest: 1.1.1
+
+published over a year ago by isaacs <i@izs.me>
+
+`
diff --git a/smoke-tests/content/abbrev.json b/smoke-tests/test/fixtures/abbrev.json
index ffcf5474a..ffcf5474a 100644
--- a/smoke-tests/content/abbrev.json
+++ b/smoke-tests/test/fixtures/abbrev.json
diff --git a/smoke-tests/content/abbrev.min.json b/smoke-tests/test/fixtures/abbrev.min.json
index c03d91c9c..c03d91c9c 100644
--- a/smoke-tests/content/abbrev.min.json
+++ b/smoke-tests/test/fixtures/abbrev.min.json
diff --git a/smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.0.4.tgz
index dfd1b5591..dfd1b5591 100644
--- a/smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz
+++ b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.0.4.tgz
Binary files differ
diff --git a/smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.1.1.tgz
index 4d9504504..4d9504504 100644
--- a/smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz
+++ b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.1.1.tgz
Binary files differ
diff --git a/smoke-tests/content/promise-all-reject-late.json b/smoke-tests/test/fixtures/promise-all-reject-late.json
index e243b92a3..e243b92a3 100644
--- a/smoke-tests/content/promise-all-reject-late.json
+++ b/smoke-tests/test/fixtures/promise-all-reject-late.json
diff --git a/smoke-tests/content/promise-all-reject-late.min.json b/smoke-tests/test/fixtures/promise-all-reject-late.min.json
index 699be7aaf..699be7aaf 100644
--- a/smoke-tests/content/promise-all-reject-late.min.json
+++ b/smoke-tests/test/fixtures/promise-all-reject-late.min.json
diff --git a/smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz b/smoke-tests/test/fixtures/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz
index 7da404423..7da404423 100644
--- a/smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz
+++ b/smoke-tests/test/fixtures/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz
Binary files differ
diff --git a/smoke-tests/test/fixtures/server.js b/smoke-tests/test/fixtures/server.js
new file mode 100644
index 000000000..b1056a221
--- /dev/null
+++ b/smoke-tests/test/fixtures/server.js
@@ -0,0 +1,49 @@
+const { join, basename } = require('path')
+const { existsSync, readFileSync } = require('fs')
+const http = require('http')
+const PORT = 12345 + (+process.env.TAP_CHILD_ID || 0)
+
+let server = null
+const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
+
+const start = () => new Promise((resolve) => {
+ server = http.createServer((req, res) => {
+ res.setHeader('connection', 'close')
+
+ const f = join(__dirname, join('/', req.url.replace(/@/, '').replace(/%2f/i, '/')))
+
+ // a magic package that causes us to return an error that will be logged
+ if (basename(f) === 'fail_reflect_user_agent') {
+ res.statusCode = 404
+ res.setHeader('npm-notice', req.headers['user-agent'])
+ return res.end()
+ }
+
+ const isCorgi = req.headers.accept.includes('application/vnd.npm.install-v1+json')
+ const file = f + (
+ isCorgi && existsSync(`${f}.min.json`) ? '.min.json'
+ : existsSync(`${f}.json`) ? '.json'
+ : existsSync(`${f}/index.json`) ? 'index.json'
+ : ''
+ )
+
+ try {
+ const body = readFileSync(file)
+ res.setHeader('content-length', body.length)
+ res.setHeader('content-type', /\.min\.json$/.test(file) ? corgiDoc
+ : /\.json$/.test(file) ? 'application/json'
+ : 'application/octet-stream')
+ res.end(body)
+ } catch {
+ res.statusCode = 500
+ res.setHeader('content-type', 'text/plain')
+ res.end('bad')
+ }
+ }).listen(PORT, resolve)
+})
+
+module.exports = {
+ start,
+ stop: () => server.close(),
+ registry: `http://localhost:${PORT}/`,
+}
diff --git a/smoke-tests/index.js b/smoke-tests/test/index.js
index 464187da0..bbb833a57 100644
--- a/smoke-tests/index.js
+++ b/smoke-tests/test/index.js
@@ -1,21 +1,47 @@
-const fs = require('fs')
-const { promisify } = require('util')
-const execAsync = promisify(require('child_process').exec)
-const { join, resolve } = require('path')
+const { readFileSync, realpathSync, mkdirSync, existsSync, writeFileSync } = require('fs')
+const spawn = require('@npmcli/promise-spawn')
+const { join, resolve, sep } = require('path')
const t = require('tap')
-const rimraf = promisify(require('rimraf'))
+const rimraf = require('rimraf')
+const which = require('which').sync
+const { start, stop, registry } = require('./fixtures/server.js')
+const { SMOKE_PUBLISH_NPM, CI, PATH } = process.env
+const log = CI ? console.error : () => {}
+
+const cwd = resolve(__dirname, '..', '..')
+const npmCli = join('bin', 'npm-cli.js')
+const execArgv = SMOKE_PUBLISH_NPM ? ['npm'] : [process.execPath, join(cwd, npmCli)]
+const npmDir = SMOKE_PUBLISH_NPM ? realpathSync(which('npm')).replace(sep + npmCli, '') : cwd
+
+// setup server
+t.before(start)
+t.teardown(stop)
+// update notifier should never be written
+t.afterEach((t) => {
+ const updateExists = existsSync(join(cacheLocation, '_update-notifier-last-checked'))
+ t.equal(updateExists, false)
+})
+
+const readFile = filename => readFileSync(resolve(localPrefix, filename), 'utf-8')
const normalizePath = path => path.replace(/[A-Z]:/, '').replace(/\\/g, '/')
-const cwd = normalizePath(process.cwd())
+
t.cleanSnapshot = s =>
s
- .split(cwd)
+ // sometimes we print normalized paths in snapshots regardless of
+ // platform so replace those first
+ .split(normalizePath(npmDir))
+ .join('{CWD}')
+ .split(normalizePath(cwd))
.join('{CWD}')
.split(registry)
.join('https://registry.npmjs.org/')
.split(normalizePath(process.execPath))
.join('node')
- .split(process.cwd())
+ // then replace platform style paths
+ .split(npmDir)
+ .join('{CWD}')
+ .split(cwd)
.join('{CWD}')
.replace(/\\+/g, '/')
.replace(/\r\n/g, '\n')
@@ -23,11 +49,6 @@ t.cleanSnapshot = s =>
.replace(/^npm@.* /gm, 'npm ')
.replace(/^.*debug-[0-9]+.log$/gm, '')
-// setup server
-const { start, stop, registry } = require('./server.js')
-t.before(start)
-t.teardown(stop)
-
// setup fixtures
const path = t.testdir({
'.npmrc': '',
@@ -37,30 +58,49 @@ const path = t.testdir({
})
const localPrefix = resolve(path, 'project')
const userconfigLocation = resolve(path, '.npmrc')
-const npmLocation = resolve(__dirname, '../bin/npm-cli.js')
const cacheLocation = resolve(path, 'cache')
const binLocation = resolve(path, 'bin')
-const env = {
- HOME: path,
- PATH: `${process.env.PATH}:${binLocation}`,
-}
-const npmOpts = [
- `--registry=${registry}`,
- `--cache="${cacheLocation}"`,
- `--userconfig="${userconfigLocation}"`,
- '--no-audit',
- '--no-update-notifier',
- '--loglevel=silly',
-].join(' ')
-const npmBin = `"${process.execPath}" "${npmLocation}" ${npmOpts}`
-const exec = async cmd => {
- const res = await execAsync(cmd, { cwd: localPrefix, env })
- if (res.stderr) {
- console.error(res.stderr)
+
+const exec = async (...args) => {
+ const cmd = []
+ const opts = [
+ `--registry=${registry}`,
+ `--cache=${cacheLocation}`,
+ `--userconfig=${userconfigLocation}`,
+ '--no-audit',
+ '--no-update-notifier',
+ '--loglevel=silly',
+ ]
+ for (const arg of args) {
+ if (arg.startsWith('--')) {
+ opts.push(arg)
+ } else {
+ cmd.push(arg)
+ }
+ }
+
+ // XXX: not sure why outdated fails with no-workspaces but works without it
+ if (!opts.includes('--workspaces') && cmd[0] !== 'outdated') {
+ // This is required so we dont detect any workspace roots above the testdir
+ opts.push('--no-workspaces')
}
- return String(res.stdout)
+
+ const spawnArgs = [execArgv[0], [...execArgv.slice(1), ...cmd, ...opts]]
+ log([spawnArgs[0], ...spawnArgs[1]].join(' '))
+
+ const res = await spawn(...spawnArgs, {
+ cwd: localPrefix,
+ env: {
+ HOME: path,
+ PATH: `${PATH}:${binLocation}`,
+ },
+ stdioString: true,
+ encoding: 'utf-8',
+ })
+
+ log(res.stderr)
+ return res.stdout
}
-const readFile = filename => String(fs.readFileSync(resolve(localPrefix, filename)))
// this test must come first, its package.json will be destroyed and the one
// created in the next test (npm init) will create a new one that must be
@@ -71,35 +111,31 @@ t.test('npm install sends correct user-agent', async t => {
name: 'smoke-test-workspaces',
workspaces: ['packages/*'],
})
- fs.writeFileSync(pkgPath, pkgContent, { encoding: 'utf8' })
+ writeFileSync(pkgPath, pkgContent, { encoding: 'utf8' })
const wsRoot = join(localPrefix, 'packages')
- fs.mkdirSync(wsRoot)
+ mkdirSync(wsRoot)
const wsPath = join(wsRoot, 'foo')
- fs.mkdirSync(wsPath)
+ mkdirSync(wsPath)
const wsPkgPath = join(wsPath, 'package.json')
const wsContent = JSON.stringify({
name: 'foo',
})
- fs.writeFileSync(wsPkgPath, wsContent, { encoding: 'utf8' })
- t.teardown(async () => {
- await rimraf(`${localPrefix}/*`)
- })
+ writeFileSync(wsPkgPath, wsContent, { encoding: 'utf8' })
+ t.teardown(() => rimraf.sync(`${localPrefix}/*`))
- const cmd = `${npmBin} install fail_reflect_user_agent`
await t.rejects(
- exec(cmd),
+ exec('install', 'fail_reflect_user_agent'),
{
stderr: /workspaces\/false/,
},
'workspaces/false is present in output'
)
- const wsCmd = `${npmBin} install fail_reflect_user_agent --workspaces`
await t.rejects(
- exec(wsCmd),
+ exec('install', 'fail_reflect_user_agent', '--workspaces'),
{
stderr: /workspaces\/true/,
},
@@ -108,29 +144,34 @@ t.test('npm install sends correct user-agent', async t => {
})
t.test('npm init', async t => {
- const cmd = `${npmBin} init -y`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('init', '-y')
t.matchSnapshot(cmdRes, 'should have successful npm init result')
- const pkg = JSON.parse(fs.readFileSync(resolve(localPrefix, 'package.json')))
+ const pkg = JSON.parse(readFileSync(resolve(localPrefix, 'package.json')))
t.equal(pkg.name, 'project', 'should have expected generated name')
t.equal(pkg.version, '1.0.0', 'should have expected generated version')
})
+t.test('npm --version', async t => {
+ const v = await exec('--version')
+
+ if (SMOKE_PUBLISH_NPM) {
+ t.match(v.trim(), /-[0-9a-f]{40}\.\d$/, 'must have a git version')
+ } else {
+ t.skip('not checking version')
+ }
+})
+
t.test('npm (no args)', async t => {
- const cmd = `"${process.execPath}" "${npmLocation}" --no-audit --no-update-notifier`
- const cmdRes = await execAsync(cmd, { cwd: localPrefix, env }).catch(err => {
- t.equal(err.code, 1, 'should exit with error code')
- return err
- })
+ const err = await exec('--loglevel=notice').catch(e => e)
- t.equal(cmdRes.stderr, '', 'should have no stderr output')
- t.matchSnapshot(String(cmdRes.stdout), 'should have expected no args output')
+ t.equal(err.code, 1, 'should exit with error code')
+ t.equal(err.stderr, '', 'should have no stderr output')
+ t.matchSnapshot(err.stdout, 'should have expected no args output')
})
t.test('npm install prodDep@version', async t => {
- const cmd = `${npmBin} install abbrev@1.0.4`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('install', 'abbrev@1.0.4')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected install reify output')
t.matchSnapshot(readFile('package.json'), 'should have expected package.json result')
@@ -138,8 +179,7 @@ t.test('npm install prodDep@version', async t => {
})
t.test('npm install dev dep', async t => {
- const cmd = `${npmBin} install -D promise-all-reject-late`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('install', 'promise-all-reject-late', '-D')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected dev dep added reify output')
t.matchSnapshot(
@@ -153,47 +193,39 @@ t.test('npm install dev dep', async t => {
})
t.test('npm ls', async t => {
- const cmd = `${npmBin} ls`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('ls')
t.matchSnapshot(cmdRes, 'should have expected ls output')
})
t.test('npm fund', async t => {
- const cmd = `${npmBin} fund`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('fund')
t.matchSnapshot(cmdRes, 'should have expected fund output')
})
t.test('npm explain', async t => {
- const cmd = `${npmBin} explain abbrev`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('explain', 'abbrev')
t.matchSnapshot(cmdRes, 'should have expected explain output')
})
t.test('npm diff', async t => {
- const cmd = `${npmBin} diff --diff=abbrev@1.0.4 --diff=abbrev@1.1.1`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('diff', '--diff=abbrev@1.0.4', '--diff=abbrev@1.1.1')
t.matchSnapshot(cmdRes, 'should have expected diff output')
})
t.test('npm outdated', async t => {
- const cmd = `${npmBin} outdated`
- const cmdRes = await exec(cmd).catch(err => {
- t.equal(err.code, 1, 'should exit with error code')
- return err
- })
+ const err = await exec('outdated').catch(e => e)
- t.not(cmdRes.stderr, '', 'should have stderr output')
- t.matchSnapshot(String(cmdRes.stdout), 'should have expected outdated output')
+ t.equal(err.code, 1, 'should exit with error code')
+ t.not(err.stderr, '', 'should have stderr output')
+ t.matchSnapshot(err.stdout, 'should have expected outdated output')
})
t.test('npm set-script', async t => {
- const cmd = `${npmBin} set-script "hello" "echo Hello"`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('set-script', 'hello', 'echo Hello')
t.matchSnapshot(cmdRes, 'should have expected set-script output')
t.matchSnapshot(
@@ -203,29 +235,25 @@ t.test('npm set-script', async t => {
})
t.test('npm run-script', async t => {
- const cmd = `${npmBin} run hello`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('run', 'hello')
t.matchSnapshot(cmdRes, 'should have expected run-script output')
})
t.test('npm prefix', async t => {
- const cmd = `${npmBin} prefix`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('prefix')
t.matchSnapshot(cmdRes, 'should have expected prefix output')
})
t.test('npm view', async t => {
- const cmd = `${npmBin} view abbrev@1.0.4`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('view', 'abbrev@1.0.4')
t.matchSnapshot(cmdRes, 'should have expected view output')
})
t.test('npm update dep', async t => {
- const cmd = `${npmBin} update abbrev`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('update', 'abbrev')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected update reify output')
t.matchSnapshot(readFile('package.json'), 'should have expected update package.json result')
@@ -233,8 +261,7 @@ t.test('npm update dep', async t => {
})
t.test('npm uninstall', async t => {
- const cmd = `${npmBin} uninstall promise-all-reject-late`
- const cmdRes = await exec(cmd)
+ const cmdRes = await exec('uninstall', 'promise-all-reject-late')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected uninstall reify output')
t.matchSnapshot(readFile('package.json'), 'should have expected uninstall package.json result')
@@ -242,12 +269,10 @@ t.test('npm uninstall', async t => {
})
t.test('npm pkg', async t => {
- let cmd = `${npmBin} pkg get license`
- let cmdRes = await exec(cmd)
+ let cmdRes = await exec('pkg', 'get', 'license')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected pkg get output')
- cmd = `${npmBin} pkg set tap[test-env][0]=LC_ALL=sk`
- cmdRes = await exec(cmd)
+ cmdRes = await exec('pkg', 'set', 'tap[test-env][0]=LC_ALL=sk')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected pkg set output')
t.matchSnapshot(
@@ -255,12 +280,10 @@ t.test('npm pkg', async t => {
'should have expected npm pkg set modified package.json result'
)
- cmd = `${npmBin} pkg get`
- cmdRes = await exec(cmd)
+ cmdRes = await exec('pkg', 'get')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should print package.json contents')
- cmd = `${npmBin} pkg delete tap`
- cmdRes = await exec(cmd)
+ cmdRes = await exec('pkg', 'delete', 'tap')
t.matchSnapshot(cmdRes.replace(/in.*s/, ''), 'should have expected pkg delete output')
t.matchSnapshot(
@@ -271,12 +294,11 @@ t.test('npm pkg', async t => {
t.test('npm update --no-save --no-package-lock', async t => {
// setup, manually reset dep value
- await exec(`${npmBin} pkg set "dependencies.abbrev==1.0.4"`)
- await exec(`${npmBin} install`)
- await exec(`${npmBin} pkg set "dependencies.abbrev=^1.0.4"`)
+ await exec('pkg', 'set', 'dependencies.abbrev==1.0.4')
+ await exec(`install`)
+ await exec('pkg', 'set', 'dependencies.abbrev=^1.0.4')
- const cmd = `${npmBin} update --no-save --no-package-lock`
- await exec(cmd)
+ await exec('update', '--no-save', '--no-package-lock')
t.equal(
JSON.parse(readFile('package.json')).dependencies.abbrev,
@@ -291,8 +313,7 @@ t.test('npm update --no-save --no-package-lock', async t => {
})
t.test('npm update --no-save', async t => {
- const cmd = `${npmBin} update --no-save`
- await exec(cmd)
+ await exec('update', '--no-save')
t.equal(
JSON.parse(readFile('package.json')).dependencies.abbrev,
@@ -307,8 +328,7 @@ t.test('npm update --no-save', async t => {
})
t.test('npm update --save', async t => {
- const cmd = `${npmBin} update --save`
- await exec(cmd)
+ await exec('update', '--save')
t.equal(
JSON.parse(readFile('package.json')).dependencies.abbrev,
@@ -323,8 +343,8 @@ t.test('npm update --save', async t => {
})
t.test('npm ci', async t => {
- await exec(`${npmBin} uninstall abbrev`)
- await exec(`${npmBin} install abbrev@1.0.4 --save-exact`)
+ await exec('uninstall', 'abbrev')
+ await exec('install', 'abbrev@1.0.4', '--save-exact')
t.equal(
JSON.parse(readFile('package-lock.json')).packages['node_modules/abbrev'].version,
@@ -332,20 +352,9 @@ t.test('npm ci', async t => {
'should have stored exact installed version'
)
- await exec(`${npmBin} pkg set "dependencies.abbrev=^1.1.1"`)
-
- try {
- const npmOpts = [
- `--registry=${registry}`,
- `--cache="${cacheLocation}"`,
- `--userconfig="${userconfigLocation}"`,
- '--no-audit',
- '--no-update-notifier',
- '--loglevel=error',
- ].join(' ')
- const npmBin = `"${process.execPath}" "${npmLocation}" ${npmOpts}`
- await exec(`${npmBin} ci`)
- } catch (err) {
- t.matchSnapshot(err.stderr, 'should throw mismatch deps in lock file error')
- }
+ await exec('pkg', 'set', 'dependencies.abbrev=^1.1.1')
+
+ const err = await exec('ci', '--loglevel=error').catch(e => e)
+ t.equal(err.code, 1)
+ t.matchSnapshot(err.stderr, 'should throw mismatch deps in lock file error')
})