diff options
author | Luke Karrys <luke@lukekarrys.com> | 2022-04-08 18:24:56 +0300 |
---|---|---|
committer | Nathan Fritz <fritzy@github.com> | 2022-04-14 00:20:48 +0300 |
commit | 672fce84b25ecbe58d311acfae6c43e5ca2d778d (patch) | |
tree | 39e8ac90263f4386284e8d93ef2bbe7f30a9f32a /smoke-tests | |
parent | 3f7fe17d1ea743b3ce1f27b9156e9fa0e358a7df (diff) |
chore: refactor smoke-tests
Diffstat (limited to 'smoke-tests')
-rw-r--r-- | smoke-tests/.eslintrc.js | 15 | ||||
-rw-r--r-- | smoke-tests/.gitignore | 21 | ||||
-rw-r--r-- | smoke-tests/package.json | 49 | ||||
-rw-r--r-- | smoke-tests/server.js | 282 | ||||
-rw-r--r-- | smoke-tests/tap-snapshots/test/index.js.test.cjs | 784 | ||||
-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) | bin | 2295 -> 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) | bin | 2301 -> 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) | bin | 30838 -> 30838 bytes | |||
-rw-r--r-- | smoke-tests/test/fixtures/server.js | 49 | ||||
-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`] = ` + +[4m[1m[32mabbrev[39m@[32m1.0.4[39m[22m[24m | [32mMIT[39m | deps: [32mnone[39m | versions: [33m8[39m +Like ruby's abbrev module, but in js +[36mhttps://github.com/isaacs/abbrev-js#readme[39m + +dist +.tarball: [36mhttps://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz[39m +.shasum: [33mbd55ae5e413ba1722ee4caba1f6ea10414a59ecd[39m + +maintainers: +- [33mnlf[39m <[36mquitlahok@gmail.com[39m> +- [33mruyadorno[39m <[36mruyadorno@hotmail.com[39m> +- [33mdarcyclarke[39m <[36mdarcy@darcyclarke.me[39m> +- [33madam_baldwin[39m <[36mevilpacket@gmail.com[39m> +- [33misaacs[39m <[36mi@izs.me[39m> + +dist-tags: +[1m[32mlatest[39m[22m: 1.1.1 + +published [33mover a year ago[39m by [33misaacs[39m <[36mi@izs.me[39m> + +` 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 Binary files differindex dfd1b5591..dfd1b5591 100644 --- a/smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz +++ b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.0.4.tgz diff --git a/smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.1.1.tgz Binary files differindex 4d9504504..4d9504504 100644 --- a/smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz +++ b/smoke-tests/test/fixtures/abbrev/-/abbrev-1.1.1.tgz 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 Binary files differindex 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 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') }) |