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
path: root/test
diff options
context:
space:
mode:
authorRuy Adorno <ruyadorno@hotmail.com>2021-04-07 18:03:41 +0300
committerRuy Adorno <ruyadorno@hotmail.com>2021-04-22 22:06:29 +0300
commit4c1f16d2c29a7a56c19b97f2820e6305a6075083 (patch)
tree460fd0dfa65b168d3f35bac5e0ad363b14684a1d /test
parent2aecec591df6866e27d0b17dc49cef8f7d738d77 (diff)
feat: add init workspaces
Add workspaces support to `npm init` - Fixes `npm exec` respecting `script-shell` option value - Refactored `lib/exec.js` into `libnpmexec` - Updates init-package-json@2.0.3 - Added ability to create a new workspace using the -w config PR-URL: https://github.com/npm/cli/pull/3095 Credit: @ruyadorno Close: #3095 Reviewed-by: @wraithgar
Diffstat (limited to 'test')
-rw-r--r--test/lib/exec.js40
-rw-r--r--test/lib/init.js481
2 files changed, 423 insertions, 98 deletions
diff --git a/test/lib/exec.js b/test/lib/exec.js
index 0c577e42f..5ecc73274 100644
--- a/test/lib/exec.js
+++ b/test/lib/exec.js
@@ -34,7 +34,7 @@ const config = {
yes: true,
call: '',
package: [],
- shell: 'shell-cmd',
+ 'script-shell': 'shell-cmd',
}
const npm = mockNpm({
flatOptions,
@@ -86,12 +86,14 @@ const PATH = require('../../lib/utils/path.js')
let CI_NAME = 'travis-ci'
const mocks = {
- '@npmcli/arborist': Arborist,
- '@npmcli/run-script': runScript,
- '@npmcli/ci-detect': () => CI_NAME,
- pacote,
- read,
- 'mkdirp-infer-owner': mkdirp,
+ libnpmexec: t.mock('libnpmexec', {
+ '@npmcli/arborist': Arborist,
+ '@npmcli/run-script': runScript,
+ '@npmcli/ci-detect': () => CI_NAME,
+ pacote,
+ read,
+ 'mkdirp-infer-owner': mkdirp,
+ }),
}
const Exec = t.mock('../../lib/exec.js', mocks)
const exec = new Exec(npm)
@@ -108,6 +110,7 @@ t.afterEach(() => {
PROGRESS_IGNORED = false
flatOptions.legacyPeerDeps = false
config.color = false
+ config['script-shell'] = 'shell-cmd'
config.package = []
flatOptions.package = []
config.call = ''
@@ -288,6 +291,29 @@ t.test('npm exec <noargs>, run interactive shell', t => {
})
})
+ t.test('not defined script-shell config value', t => {
+ CI_NAME = null
+ process.stdin.isTTY = true
+ config['script-shell'] = undefined
+
+ exec.exec([], er => {
+ if (er)
+ throw er
+
+ t.match(RUN_SCRIPTS, [{
+ pkg: { scripts: { npx: undefined } },
+ }])
+
+ LOG_WARN.length = 0
+ ARB_CTOR.length = 0
+ MKDIRPS.length = 0
+ ARB_REIFY.length = 0
+ OUTPUT.length = 0
+ RUN_SCRIPTS.length = 0
+ t.end()
+ })
+ })
+
t.end()
})
diff --git a/test/lib/init.js b/test/lib/init.js
index 11273e4c3..0964bb5ce 100644
--- a/test/lib/init.js
+++ b/test/lib/init.js
@@ -1,3 +1,5 @@
+const fs = require('fs')
+const { resolve } = require('path')
const t = require('tap')
const mockNpm = require('../fixtures/mock-npm')
@@ -12,121 +14,195 @@ const npmLog = {
}
const config = {
'init-module': '~/.npm-init.js',
+ yes: true,
}
const npm = mockNpm({
config,
log: npmLog,
- commands: {},
output: (...msg) => {
result += msg.join('\n')
},
})
const mocks = {
- 'init-package-json': (dir, initFile, config, cb) => cb(null, 'data'),
'../../lib/utils/usage.js': () => 'usage instructions',
}
const Init = t.mock('../../lib/init.js', mocks)
const init = new Init(npm)
+const _cwd = process.cwd()
+const _consolelog = console.log
+const noop = () => {}
t.afterEach(() => {
result = ''
+ config.yes = true
config.package = undefined
- npm.commands = {}
npm.log = npmLog
+ process.chdir(_cwd)
+ console.log = _consolelog
})
-t.test('classic npm init no args', t => {
+t.test('classic npm init -y', t => {
+ npm.localPrefix = t.testdir({})
+
+ // init-package-json prints directly to console.log
+ // this avoids poluting test output with those logs
+ console.log = noop
+
+ process.chdir(npm.localPrefix)
init.exec([], err => {
- t.error(err, 'npm init no args')
- t.matchSnapshot(result, 'should print helper info')
+ if (err)
+ throw err
+
+ const pkg = require(resolve(npm.localPrefix, 'package.json'))
+ t.equal(pkg.version, '1.0.0')
+ t.equal(pkg.license, 'ISC')
t.end()
})
})
-t.test('classic npm init -y', t => {
- t.plan(7)
- config.yes = true
- Object.defineProperty(npm, 'flatOptions', { value: { yes: true} })
- npm.log = { ...npm.log }
- npm.log.silly = (title, msg) => {
- t.equal(title, 'package data', 'should print title')
- t.equal(msg, 'data', 'should print pkg data info')
- }
- npm.log.resume = () => {
- t.ok('should resume logs')
- }
- npm.log.info = (title, msg) => {
- t.equal(title, 'init', 'should print title')
- t.equal(msg, 'written successfully', 'should print done info')
- }
+t.test('classic interactive npm init', t => {
+ npm.localPrefix = t.testdir({})
+ config.yes = undefined
+
+ const Init = t.mock('../../lib/init.js', {
+ ...mocks,
+ 'init-package-json': (path, initFile, config, cb) => {
+ t.equal(
+ path,
+ resolve(npm.localPrefix),
+ 'should start init package.json in expected path'
+ )
+ cb()
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec([], err => {
- t.error(err, 'npm init -y')
- t.equal(result, '')
+ if (err)
+ throw err
+
+ t.end()
})
})
t.test('npm init <arg>', t => {
- t.plan(3)
- npm.commands.exec = (arr, cb) => {
- t.same(config.package, [], 'should set empty array value')
- t.same(
- arr,
- ['create-react-app'],
- 'should npx with listed packages'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['create-react-app'],
+ 'should npx with listed packages'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['react-app'], err => {
- t.error(err, 'npm init react-app')
+ if (err)
+ throw err
+ })
+})
+
+t.test('npm init <arg> -- other-args', t => {
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['create-react-app', 'my-path', '--some-option', 'some-value'],
+ 'should npm exec with expected args'
+ )
+ },
})
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
+ init.exec(
+ ['react-app', 'my-path', '--some-option', 'some-value'],
+ err => {
+ if (err)
+ throw err
+ }
+ )
})
t.test('npm init @scope/name', t => {
- t.plan(2)
- npm.commands.exec = (arr, cb) => {
- t.same(
- arr,
- ['@npmcli/create-something'],
- 'should npx with scoped packages'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['@npmcli/create-something'],
+ 'should npx with scoped packages'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['@npmcli/something'], err => {
- t.error(err, 'npm init init @scope/name')
+ if (err)
+ throw err
})
})
t.test('npm init git spec', t => {
- t.plan(2)
- npm.commands.exec = (arr, cb) => {
- t.same(
- arr,
- ['npm/create-something'],
- 'should npx with git-spec packages'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['npm/create-something'],
+ 'should npx with git-spec packages'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['npm/something'], err => {
- t.error(err, 'npm init init @scope/name')
+ if (err)
+ throw err
})
})
t.test('npm init @scope', t => {
- t.plan(2)
- npm.commands.exec = (arr, cb) => {
- t.same(
- arr,
- ['@npmcli/create'],
- 'should npx with @scope/create pkgs'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['@npmcli/create'],
+ 'should npx with @scope/create pkgs'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['@npmcli'], err => {
- t.error(err, 'npm init init @scope/create')
+ if (err)
+ throw err
})
})
t.test('npm init tgz', t => {
+ npm.localPrefix = t.testdir({})
+
+ process.chdir(npm.localPrefix)
init.exec(['something.tgz'], err => {
t.match(
err,
@@ -138,24 +214,38 @@ t.test('npm init tgz', t => {
})
t.test('npm init <arg>@next', t => {
- t.plan(2)
- npm.commands.exec = (arr, cb) => {
- t.same(
- arr,
- ['create-something@next'],
- 'should npx with something@next'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: ({ args }) => {
+ t.same(
+ args,
+ ['create-something@next'],
+ 'should npx with something@next'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['something@next'], err => {
- t.error(err, 'npm init init something@next')
+ if (err)
+ throw err
})
})
t.test('npm init exec error', t => {
- npm.commands.exec = (arr, cb) => {
- cb(new Error('ERROR'))
- }
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: async ({ args }) => {
+ throw new Error('ERROR')
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['something@next'], err => {
t.match(
err,
@@ -167,23 +257,31 @@ t.test('npm init exec error', t => {
})
t.test('should not rewrite flatOptions', t => {
- t.plan(3)
- npm.commands.exec = (arr, cb) => {
- t.same(config.package, [], 'should set empty array value')
- t.same(
- arr,
- ['create-react-app', 'my-app'],
- 'should npx with extra args'
- )
- cb()
- }
+ t.plan(1)
+ npm.localPrefix = t.testdir({})
+
+ const Init = t.mock('../../lib/init.js', {
+ libnpmexec: async ({ args }) => {
+ t.same(
+ args,
+ ['create-react-app', 'my-app'],
+ 'should npx with extra args'
+ )
+ },
+ })
+ const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec(['react-app', 'my-app'], err => {
- t.error(err, 'npm init react-app')
+ if (err)
+ throw err
})
})
t.test('npm init cancel', t => {
- t.plan(3)
+ t.plan(2)
+ npm.localPrefix = t.testdir({})
+
const Init = t.mock('../../lib/init.js', {
...mocks,
'init-package-json': (dir, initFile, config, cb) => cb(
@@ -196,12 +294,17 @@ t.test('npm init cancel', t => {
t.equal(title, 'init', 'should have init title')
t.equal(msg, 'canceled', 'should log canceled')
}
+
+ process.chdir(npm.localPrefix)
init.exec([], err => {
- t.error(err, 'npm init cancel')
+ if (err)
+ throw err
})
})
t.test('npm init error', t => {
+ npm.localPrefix = t.testdir({})
+
const Init = t.mock('../../lib/init.js', {
...mocks,
'init-package-json': (dir, initFile, config, cb) => cb(
@@ -209,8 +312,204 @@ t.test('npm init error', t => {
),
})
const init = new Init(npm)
+
+ process.chdir(npm.localPrefix)
init.exec([], err => {
t.match(err, /Unknown Error/, 'should throw error')
t.end()
})
})
+
+t.test('workspaces', t => {
+ t.test('no args', t => {
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ }),
+ })
+
+ const Init = t.mock('../../lib/init.js', {
+ ...mocks,
+ 'init-package-json': (dir, initFile, config, cb) => {
+ t.equal(dir, resolve(npm.localPrefix, 'a'), 'should use the ws path')
+ cb()
+ },
+ })
+ const init = new Init(npm)
+ init.execWorkspaces([], ['a'], err => {
+ if (err)
+ throw err
+
+ t.matchSnapshot(result, 'should print helper info')
+ t.end()
+ })
+ })
+
+ t.test('no args, existing folder', t => {
+ // init-package-json prints directly to console.log
+ // this avoids poluting test output with those logs
+ console.log = noop
+
+ npm.localPrefix = t.testdir({
+ packages: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ }),
+ },
+ },
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ workspaces: ['packages/a'],
+ }),
+ })
+
+ init.execWorkspaces([], ['packages/a'], err => {
+ if (err)
+ throw err
+
+ t.matchSnapshot(result, 'should print helper info')
+ t.end()
+ })
+ })
+
+ t.test('with arg but missing workspace folder', t => {
+ // init-package-json prints directly to console.log
+ // this avoids poluting test output with those logs
+ console.log = noop
+
+ npm.localPrefix = t.testdir({
+ node_modules: {
+ a: t.fixture('symlink', '../a'),
+ 'create-index': {
+ 'index.js': ``,
+ },
+ },
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ }),
+ },
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ }),
+ })
+
+ init.execWorkspaces([], ['packages/a'], err => {
+ if (err)
+ throw err
+
+ t.matchSnapshot(result, 'should print helper info')
+ t.end()
+ })
+ })
+
+ t.test('fail parsing top-level package.json to set workspace', t => {
+ // init-package-json prints directly to console.log
+ // this avoids poluting test output with those logs
+ console.log = noop
+
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ }),
+ })
+
+ const Init = t.mock('../../lib/init.js', {
+ ...mocks,
+ 'json-parse-even-better-errors': () => {
+ throw new Error('ERR')
+ },
+ })
+ const init = new Init(npm)
+
+ init.execWorkspaces([], ['a'], err => {
+ t.match(
+ err,
+ /Invalid package.json: Error: ERR/,
+ 'should exit with error'
+ )
+ t.end()
+ })
+ })
+
+ t.test('missing top-level package.json when settting workspace', t => {
+ // init-package-json prints directly to console.log
+ // this avoids poluting test output with those logs
+ console.log = noop
+
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ }),
+ })
+
+ const Init = t.mock('../../lib/init.js', {
+ ...mocks,
+ fs: {
+ statSync () {
+ return true
+ },
+ readFileSync () {
+ throw new Error('ERR')
+ },
+ },
+ })
+ const init = new Init(npm)
+
+ init.execWorkspaces([], ['a'], err => {
+ t.match(
+ err,
+ /package.json not found/,
+ 'should exit with error'
+ )
+ t.end()
+ })
+ })
+
+ t.test('using args', t => {
+ npm.localPrefix = t.testdir({
+ b: {
+ 'package.json': JSON.stringify({
+ name: 'b',
+ }),
+ },
+ 'package.json': JSON.stringify({
+ name: 'top-level',
+ workspaces: ['b'],
+ }),
+ })
+
+ const Init = t.mock('../../lib/init.js', {
+ ...mocks,
+ libnpmexec: ({ args, path }) => {
+ t.same(
+ args,
+ ['create-react-app'],
+ 'should npx with listed packages'
+ )
+ t.same(
+ path,
+ resolve(npm.localPrefix, 'a'),
+ 'should use workspace path'
+ )
+ fs.writeFileSync(
+ resolve(npm.localPrefix, 'a/package.json'),
+ JSON.stringify({ name: 'a' })
+ )
+ },
+ })
+
+ const init = new Init(npm)
+ init.execWorkspaces(['react-app'], ['a'], err => {
+ if (err)
+ throw err
+
+ t.end()
+ })
+ })
+
+ t.end()
+})