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:
authornlf <quitlahok@gmail.com>2021-03-30 18:05:41 +0300
committerGar <gar+gh@danger.computer>2021-04-01 00:01:07 +0300
commitec520ce32d5e834a32ebd58491df4200e01ce690 (patch)
tree94954aea6f6291354efd5a6a7fddf981365164eb /test
parent8bcc5d73f35434e781ff56419dd7f0c380efd072 (diff)
feat(set-script): implement workspaces
Implements workspaces for set-script, also refactors tests to mock as little as possible. PR-URL: https://github.com/npm/cli/pull/2998 Credit: @nlf Close: #2998 Reviewed-by: @wraithgar
Diffstat (limited to 'test')
-rw-r--r--test/lib/set-script.js236
1 files changed, 120 insertions, 116 deletions
diff --git a/test/lib/set-script.js b/test/lib/set-script.js
index dc00fd374..0071fa20f 100644
--- a/test/lib/set-script.js
+++ b/test/lib/set-script.js
@@ -1,195 +1,199 @@
const test = require('tap')
const requireInject = require('require-inject')
+const fs = require('fs')
const parseJSON = require('json-parse-even-better-errors')
+const mockNpm = require('../fixtures/mock-npm.js')
+const { resolve } = require('path')
+
+const flatOptions = {}
+const npm = mockNpm(flatOptions)
+
+const ERROR_OUTPUT = []
+const WARN_OUTPUT = []
+const SetScript = requireInject('../../lib/set-script.js', {
+ npmlog: {
+ error: (...args) => {
+ ERROR_OUTPUT.push(args)
+ },
+ warn: (...args) => {
+ WARN_OUTPUT.push(args)
+ },
+ },
+})
+const setScript = new SetScript(npm)
test.test('completion', t => {
- const SetScript = requireInject('../../lib/set-script.js')
- const emptyDir = t.testdir()
t.test('already have a script name', async t => {
- const setScript = new SetScript({localPrefix: emptyDir})
+ npm.localPrefix = t.testdir({})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}})
t.equal(res, undefined)
t.end()
})
+
t.test('no package.json', async t => {
- const setScript = new SetScript({localPrefix: emptyDir})
+ npm.localPrefix = t.testdir({})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, [])
t.end()
})
+
t.test('has package.json, no scripts', async t => {
- const localPrefix = t.testdir({
+ npm.localPrefix = t.testdir({
'package.json': JSON.stringify({}),
})
- const setScript = new SetScript({localPrefix})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, [])
t.end()
})
+
t.test('has package.json, with scripts', async t => {
- const localPrefix = t.testdir({
+ npm.localPrefix = t.testdir({
'package.json': JSON.stringify({
scripts: { hello: 'echo hello', world: 'echo world' },
}),
})
- const setScript = new SetScript({localPrefix})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, ['hello', 'world'])
t.end()
})
+
t.end()
})
+
test.test('fails on invalid arguments', (t) => {
- const SetScript = requireInject('../../lib/set-script.js', {
- npmlog: {},
- })
- const setScript = new SetScript({})
t.plan(3)
setScript.exec(['arg1'], (fail) => t.match(fail, /Expected 2 arguments: got 1/))
setScript.exec(['arg1', 'arg2', 'arg3'], (fail) => t.match(fail, /Expected 2 arguments: got 3/))
setScript.exec(['arg1', 'arg2', 'arg3', 'arg4'], (fail) => t.match(fail, /Expected 2 arguments: got 4/))
})
+
test.test('fails if run in postinstall script', (t) => {
- const originalVar = process.env.npm_lifecycle_event
- process.env.npm_lifecycle_event = 'postinstall'
- const SetScript = requireInject('../../lib/set-script.js', {
- npmlog: {},
+ const lifecycleEvent = process.env.npm_lifecycle_event
+ t.teardown(() => {
+ process.env.npm_lifecycle_event = lifecycleEvent
})
+
+ process.env.npm_lifecycle_event = 'postinstall'
t.plan(1)
- const setScript = new SetScript({})
setScript.exec(['arg1', 'arg2'], (fail) => t.equal(fail.toString(), 'Error: Scripts can’t set from the postinstall script'))
- process.env.npm_lifecycle_event = originalVar
})
+
test.test('fails when package.json not found', (t) => {
- const SetScript = requireInject('../../lib/set-script.js')
- const setScript = new SetScript({})
t.plan(1)
setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /package.json not found/))
})
+
test.test('fails on invalid JSON', (t) => {
- const SetScript = requireInject('../../lib/set-script.js', {
- '../../lib/utils/config/definitions.js': {},
- fs: {
- readFile: () => {}, // read-package-json-fast explodes w/o this
- readFileSync: (name, charcode) => {
- return 'iamnotjson'
- },
- },
+ npm.localPrefix = t.testdir({
+ 'package.json': 'iamnotjson',
})
- const setScript = new SetScript({})
+
t.plan(1)
setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /Invalid package.json: JSONParseError/))
})
+
test.test('creates scripts object', (t) => {
- var mockFile = ''
- const SetScript = requireInject('../../lib/set-script.js', {
- '../../lib/utils/config/definitions.js': {},
- fs: {
- readFileSync: (name, charcode) => {
- return '{}'
- },
- writeFileSync: (location, inner) => {
- mockFile = inner
- },
- },
- 'read-package-json-fast': async function (filename) {
- return {
- [Symbol.for('indent')]: ' ',
- [Symbol.for('newline')]: '\n',
- }
- },
+ npm.localPrefix = t.testdir({
+ 'package.json': '{}',
})
- const setScript = new SetScript({})
+
t.plan(2)
setScript.exec(['arg1', 'arg2'], (error) => {
t.equal(error, undefined)
- t.assert(parseJSON(mockFile), {scripts: {arg1: 'arg2'}})
+ const contents = fs.readFileSync(resolve(npm.localPrefix, 'package.json'))
+ t.assert(parseJSON(contents), {scripts: {arg1: 'arg2'}})
})
})
-test.test('warns before overwriting', (t) => {
- var warningListened = ''
- const SetScript = requireInject('../../lib/set-script.js', {
- '../../lib/utils/config/definitions.js': {},
- fs: {
- readFileSync: (name, charcode) => {
- return JSON.stringify({
- scripts: {
- arg1: 'blah',
- },
- })
- },
- writeFileSync: (name, content) => {},
- },
- 'read-package-json-fast': async function (filename) {
- return {
- [Symbol.for('indent')]: ' ',
- [Symbol.for('newline')]: '\n',
- }
- },
- npmlog: {
- warn: (prefix, message) => {
- warningListened = message
+
+test.test('warns when overwriting', (t) => {
+ WARN_OUTPUT.length = 0
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ scripts: {
+ arg1: 'blah',
},
- },
+ }),
})
- const setScript = new SetScript({})
+
t.plan(2)
setScript.exec(['arg1', 'arg2'], (error) => {
t.equal(error, undefined, 'no error')
- t.equal(warningListened, 'Script "arg1" was overwritten')
+ t.hasStrict(WARN_OUTPUT[0], ['set-script', 'Script "arg1" was overwritten'], 'warning was logged')
})
})
+
test.test('provided indentation and eol is used', (t) => {
- var mockFile = ''
- const SetScript = requireInject('../../lib/set-script.js', {
- '../../lib/utils/config/definitions.js': {},
- fs: {
- readFileSync: (name, charcode) => {
- return '{}'
- },
- writeFileSync: (name, content) => {
- mockFile = content
- },
- },
- 'read-package-json-fast': async function (filename) {
- return {
- [Symbol.for('indent')]: ' '.repeat(6),
- [Symbol.for('newline')]: '\r\n',
- }
- },
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ }, null, ' '.repeat(6)).replace(/\n/g, '\r\n'),
})
- const setScript = new SetScript({})
+
t.plan(3)
setScript.exec(['arg1', 'arg2'], (error) => {
t.equal(error, undefined)
- t.equal(mockFile.split('\r\n').length > 1, true)
- t.equal(mockFile.split('\r\n').every((value) => !value.startsWith(' ') || value.startsWith(' '.repeat(6))), true)
+ // rather than checking every line's content
+ // we parse the result and verify the symbols match
+ const contents = fs.readFileSync(resolve(npm.localPrefix, 'package.json'))
+ const data = parseJSON(contents)
+ t.equal(data[Symbol.for('indent')], ' '.repeat(6), 'keeps indenting')
+ t.equal(data[Symbol.for('newline')], '\r\n', 'keeps newlines')
})
})
-test.test('goes to default when undefined indent and eol provided', (t) => {
- var mockFile = ''
- const SetScript = requireInject('../../lib/set-script.js', {
- '../../lib/utils/config/definitions.js': {},
- fs: {
- readFileSync: (name, charcode) => {
- return '{}'
- },
- writeFileSync: (name, content) => {
- mockFile = content
- },
+
+test.test('workspaces', (t) => {
+ ERROR_OUTPUT.length = 0
+ WARN_OUTPUT.length = 0
+ npm.localPrefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
+ }),
+ 'workspace-a': {
+ 'package.json': '{}',
+ },
+ 'workspace-b': {
+ 'package.json': '"notjson"',
},
- 'read-package-json-fast': async function (filename) {
- return {
- [Symbol.for('indent')]: undefined,
- [Symbol.for('newline')]: undefined,
- }
+ 'workspace-c': {
+ 'package.json': JSON.stringify({
+ scripts: {
+ arg1: 'test',
+ },
+ }, null, ' '.repeat(6)).replace(/\n/g, '\r\n'),
},
})
- const setScript = new SetScript({})
- t.plan(3)
- setScript.exec(['arg1', 'arg2'], (error) => {
- t.equal(error, undefined)
- t.equal(mockFile.split('\n').length > 1, true)
- t.equal(mockFile.split('\n').every((value) => !value.startsWith(' ') || value.startsWith(' ')), true)
+
+ setScript.execWorkspaces(['arg1', 'arg2'], [], (error) => {
+ t.equal(error, undefined, 'did not callback with an error')
+ t.equal(process.exitCode, 1, 'did set the exitCode to 1')
+ // force the exitCode back to 0 to make tap happy
+ process.exitCode = 0
+
+ // workspace-a had the script added
+ const contentsA = fs.readFileSync(resolve(npm.localPrefix, 'workspace-a', 'package.json'))
+ const dataA = parseJSON(contentsA)
+ t.hasStrict(dataA, { scripts: { arg1: 'arg2' } }, 'defined the script')
+
+ // workspace-b logged an error
+ t.match(ERROR_OUTPUT, [
+ ['set-script', `Cannot create property 'scripts' on string 'notjson'`],
+ [' in workspace: workspace-b'],
+ [` at location: ${resolve(npm.localPrefix, 'workspace-b')}`],
+ ], 'logged workspace-b error')
+
+ // workspace-c overwrite a script and logged a warning
+ const contentsC = fs.readFileSync(resolve(npm.localPrefix, 'workspace-c', 'package.json'))
+ const dataC = parseJSON(contentsC)
+ t.hasStrict(dataC, { scripts: { arg1: 'arg2' } }, 'defined the script')
+ t.equal(dataC[Symbol.for('indent')], ' '.repeat(6), 'kept the correct indent')
+ t.equal(dataC[Symbol.for('newline')], '\r\n', 'kept the correct newline')
+ t.match(WARN_OUTPUT, [
+ ['set-script', 'Script "arg1" was overwritten'],
+ [' in workspace: workspace-c'],
+ [` at location: ${resolve(npm.localPrefix, 'workspace-c')}`],
+ ], 'logged workspace-c warning')
+ t.end()
})
})