diff --git a/.travis.yml b/.travis.yml index 4db7562..5c0750e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,9 @@ node_js: - "0.12" - "0.10" +install: + - npm install + script: - npm test diff --git a/README.md b/README.md index 140d6ae..0d0e888 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Based on `npm outdated`, **updtr** installs the latest version and runs `npm test` for each dependency. If the test succeeds, **updtr** saves the new version number to your `package.json`. If the test fails, however, **updtr** rolls back its changes. +Additionally, it will use `yarn` instead of `npm` when a `yarn.lock` file is present in your project. + Made by [Peerigon](https://peerigon.com/?pk_campaign=gh-os&pk_kwd=updtr). ![updtr](assets/updtr.gif) @@ -34,7 +36,7 @@ npm install -g updtr -h, --help output usage information -V, --version output the version number - -R, --reporter choose reporter: default, shy + -R, --reporter choose reporter: default, shy, simple -w, --wanted updates to wanted version specified in package.json instead of the modules latest version -t, --test change the command for the tests -e, --exclude exclude modules comma seperated, e.g. updtr --exclude module1,module2 diff --git a/lib/filter.js b/lib/filter.js index 6b01d1d..3fb2a71 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -2,8 +2,8 @@ var semver = require("semver"); -function isGitDependency(info) { - return info.latest === "git"; +function isExoticDependency(info) { + return ["git", "exotic"].indexOf(info.latest) !== -1; } function isAlreadyInstalled(info) { @@ -27,7 +27,7 @@ function isCurrentGreaterThanUpdateTo(info) { function filter(config) { return function (info) { - return isGitDependency(info) === false && + return isExoticDependency(info) === false && isAlreadyInstalled(info) === false && isUnstable(info) === false && isExcluded(info, config.exclude) === false && diff --git a/lib/run.js b/lib/run.js index 689f257..07a9ffe 100644 --- a/lib/run.js +++ b/lib/run.js @@ -4,14 +4,16 @@ var async = require("async"); var childProcess = require("child_process"); var filter = require("./filter"); var EventEmitter = require("./EventEmitter.js"); +var fs = require("fs"); +var path = require("path"); -var defaultTestCmd = "npm test"; +var defaultTestCmdNpm = "npm test"; +var defaultTestCmdYarn = "yarn test"; function run(config, done) { var emitter = new EventEmitter(); var testCmd; var reporter; - var cwd; function exec(cmd, cb) { childProcess.exec(cmd, { maxBuffer: Infinity, encoding: "utf8", cwd: config.cwd }, cb); @@ -22,25 +24,28 @@ function run(config, done) { done(err || null); } + if (typeof config.cwd !== "string") { + throw new Error("Cannot run updtr: cwd missing"); + } + sanitizeConfig(config); + if (config.registry && config.useYarn) { + throw new Error("`yarn add` does not support custom registries yet. Please use a .npmrc file to achieve this."); + } + reporter = config.reporter; - cwd = config.cwd; testCmd = config.testCmd; - if (typeof cwd !== "string") { - throw new Error("Cannot run updtr: cwd missing"); - } - reporter(emitter); emitter.emit("init", { cwd: config.cwd }); - exec("npm outdated --json --long --depth=0", function (err, stdout) { + exec(config.useYarn ? "yarn outdated --json --flat" : "npm outdated --json --long --depth=0", function (err, stdout) { var missing; var outdated; - var infos; + var infos = []; var tasks; function createTask(info, index) { @@ -50,19 +55,21 @@ function run(config, done) { total: tasks.length, info: info, testCmd: testCmd, - installCmd: "npm i" + (config.registry ? (" --registry " + config.registry) : "") + installCmd: (config.useYarn ? "yarn add" : "npm i") + (config.registry ? (" --registry " + config.registry) : "") }; var testStdout; - var installCmd = event.installCmd + " " + info.name + "@" + info.updateTo + " " + info.saveCmd; + var installCmd; - if (config.saveExact) { - installCmd += " --save-exact"; + if (!config.useYarn && config.saveExact) { + event.installCmd += " --save-exact"; } + installCmd = event.installCmd + " " + info.name + "@" + info.updateTo + " " + info.saveCmd; + emitter.emit("updating", event); async.series({ - deleteOldVersion: async.apply(exec, "npm remove " + info.name + " " + info.saveCmd), + deleteOldVersion: async.apply(exec, (config.useYarn ? "yarn remove " : "npm remove ") + info.name + " " + info.saveCmd), installNewVersion: async.apply(exec, installCmd), emitTestingEvent: function (done) { emitter.emit("testing", event); @@ -113,7 +120,22 @@ function run(config, done) { } outdated = JSON.parse(stdout); - infos = Object.keys(outdated) + if (config.useYarn) { + if ("data" in outdated && outdated.data.body instanceof Array) { + infos = outdated.data.body.map(function (info) { + return { + name: info[0], + current: info[1], + saveCmd: info[4] === "devDependencies" ? "--dev" : "", + type: info[4], + wanted: info[2], + latest: info[3], + updateTo: config.wanted ? info[2] : info[3] + }; + }); + } + } else { + infos = Object.keys(outdated) .map(function (moduleName) { var info = outdated[moduleName]; @@ -122,8 +144,10 @@ function run(config, done) { info.updateTo = config.wanted ? info.wanted : info.latest; return info; - }) - .filter(filter(config)); + }); + } + + infos = infos.filter(filter(config)); missing = modulesMissing(infos); if (missing.length > 0) { @@ -166,8 +190,9 @@ function modulesMissing(infos) { } function sanitizeConfig(config) { + config.useYarn = fs.existsSync(path.resolve(config.cwd, "yarn.lock")); config.reporter = config.reporter || Function.prototype; - config.testCmd = config.testCmd || defaultTestCmd; + config.testCmd = config.testCmd || (config.useYarn ? defaultTestCmdYarn : defaultTestCmdNpm); config.exclude = config.exclude && config.exclude.split(",").map(function (name) { return name.trim(); }) || []; diff --git a/package.json b/package.json index 6aa43eb..d907668 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "eslint-plugin-jsdoc": "^2.3.1", "istanbul": "^0.4.3", "mocha": "^2.3.3", + "rewire": "^2.5.2", "sinon": "^1.17.4", "sinon-chai": "^2.8.0" }, diff --git a/test/run-yarn.js b/test/run-yarn.js new file mode 100644 index 0000000..5ec17a6 --- /dev/null +++ b/test/run-yarn.js @@ -0,0 +1,761 @@ +"use strict"; + +var childProcess = require("child_process"); +var sinon = require("sinon"); +var chai = require("chai"); +var sinonChai = require("sinon-chai"); +var rewire = require("rewire"); +var run = rewire("../lib/run"); + +var expect = chai.expect; +var execBackup; +var noOutdatedModules = {}; +var outdatedModules = { + type: "table", + data: { + head: ["Package", "Current", "Wanted", "Latest", "Package Type", "URL"], + body: [ + [ + "unicons", + "0.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ] + ] + } +}; +var outdatedModulesExclude = { + type: "table", + data: { + head: ["Package", "Current", "Wanted", "Latest", "Package Type", "URL"], + body: [ + [ + "servus.js", + "1.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ], [ + "servus.jsShouldNotBeExclued", + "1.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ], [ + "unicons", + "0.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ] + ] + } +}; +var expectedOptionsExclude = { + infos: [ + { + current: "1.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "servus.jsShouldNotBeExclued", + saveCmd: "", + updateTo: "2.0.0" + }, + { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + } + ], + total: 2 +}; +var outdatedModulesUnstable = { + type: "table", + data: { + head: ["Package", "Current", "Wanted", "Latest", "Package Type", "URL"], + body: [ + [ + "servus.js", + "0.1.4", + "1.1.5", + "2.0.0-beta", + "dependencies" + ], [ + "xunit-file", + "0.1.4", + "1.1.5", + "2.0.0-alpha", + "dependencies" + ], [ + "npm-stats", + "0.1.4", + "1.1.5", + "2.0.0-rc", + "dependencies" + ], [ + "unicons", + "0.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ] + ] + } +}; +var expectedOptionsUnstable = { + infos: [{ + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + }], + total: 1 +}; +var outdatedModulesWithGitDependencies = { + type: "table", + data: { + head: ["Package", "Current", "Wanted", "Latest", "Package Type", "URL"], + body: [ + [ + "unicons", + "0.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ], [ + "xunit-file", + "0.0.7", + "exotic", + "exotic", + "dependencies" + ], [ + "servus.js", + "0.0.1", + "exotic", + "exotic", + "dependencies" + ] + ] + } +}; +var outdatedModulesWithVersionGreaterThanLatestInstalled = { + type: "table", + data: { + head: ["Package", "Current", "Wanted", "Latest", "Package Type", "URL"], + body: [ + [ + "xunit-file", + "0.1.4", + "1.1.5", + "2.0.0", + "dependencies" + ], [ + "unicons", + "0.1.0", + "0.0.5", + "0.0.5", + "dependencies" + ], [ + "servus.js", + "0.1.0-alpha", + "0.0.5", + "0.0.5", + "dependencies" + ], [ + "babel-eslint", + "6.0.0-beta.6", + "5.0.0", + "5.0.0", + "dependencies" + ] + ] + } +}; +var expectedOptionsWithVersionGreaterThanLatestInstalled = { + infos: [{ + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "xunit-file", + saveCmd: "", + updateTo: "2.0.0" + }], + total: 1 +}; +var expectedOptions = { + infos: [{ + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + }], + total: 1 +}; +var expectedOptionsWithCurrentCountLatest = { + current: 1, + total: 1, + info: { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + }, + testCmd: "yarn test", + installCmd: "yarn add" +}; +var expectedOptionsWithCurrentCountLatestAndCustomTestCmd = { + current: 1, + total: 1, + info: { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + }, + testCmd: "yarn run test", + installCmd: "yarn add" +}; +var expectedOptionsWithCurrentCountLatestAndTestErrors = { + current: 1, + total: 1, + info: { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "2.0.0" + }, + testCmd: "yarn test", + installCmd: "yarn add", + testStdout: "This is the test error stdout" +}; +var expectedOptionsWithCurrentCountWanted = { + current: 1, + total: 1, + info: { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + type: "dependencies", + name: "unicons", + saveCmd: "", + updateTo: "1.1.5" + }, + testCmd: "yarn test", + installCmd: "yarn add" +}; + +function tearDown() { + childProcess.exec = execBackup; +} + +function execMock(object, testsExpectToPass) { + return function (cmd, obj, cb) { + if (cmd === "yarn outdated --json --flat") { + setImmediate(cb, null, JSON.stringify(object), null); + } else if (cmd === "yarn test" && !testsExpectToPass) { + setImmediate(cb, new Error("test failed"), "This is the test error stdout", "This is the test error stderr"); + } else { + setImmediate(cb, null); + } + }; +} + +function setupOutdatedModules(obj, testsExpectToPass) { + return function () { + execBackup = childProcess.exec; + childProcess.exec = execMock(obj, testsExpectToPass); + }; +} + +chai.use(sinonChai); + +describe("yarn run()", function () { + var fsMock = { + existsSync: function () { + return true; + } + }; + + run.__set__("fs", fsMock); + + it("should throw an error, if no options set", function () { + expect(run).to.throw(Error); + }); + + it("should throw an error, if cwd is missing", function () { + expect(function () { + run({ cwd: 1 }); + }).to.throw(Error); + }); + + describe("events", function () { + describe("init", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted, if cwd is set", function (done) { + var onInit = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("init", onInit); + } + }, function (err) { + expect(onInit).to.have.been.calledOnce; + expect(onInit).to.have.been.calledWithExactly({ cwd: process.cwd() }); + done(err); + }); + }); + }); + + describe("noop", function () { + beforeEach(setupOutdatedModules(noOutdatedModules)); + afterEach(tearDown); + + it("should be emitted if no outdated modules were found", function (done) { + var onNoop = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("noop", onNoop); + } + }, function (err) { + expect(onNoop).to.have.been.calledOnce; + expect(onNoop).to.have.been.calledWithExactly(); + done(err); + }); + }); + }); + + describe("noop", function () { + beforeEach(setupOutdatedModules(undefined)); + afterEach(tearDown); + + it("should be emitted if npm outdated returns nothing", function (done) { + var onNoop = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("noop", onNoop); + } + }, function (err) { + expect(onNoop).to.have.been.calledOnce; + expect(onNoop).to.have.been.calledWithExactly(); + done(err); + }); + }); + }); + + describe("outdated", function () { + describe("if outdated modules were found", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptions); + done(err); + }); + }); + }); + + describe("if outdated modules were found with excluded one module", function () { + beforeEach(setupOutdatedModules(outdatedModulesExclude)); + afterEach(tearDown); + + it("should be emitted without excluded module", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + exclude: "servus.js", + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptionsExclude); + done(err); + }); + }); + }); + + describe("if outdated modules were found with excluded more modules", function () { + beforeEach(setupOutdatedModules(outdatedModulesExclude)); + afterEach(tearDown); + + it("should be emitted without excluded modules", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + exclude: "asdf, servus.js", + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptionsExclude); + done(err); + }); + }); + }); + + describe("if outdated modules were found with unstable modules", function () { + beforeEach(setupOutdatedModules(outdatedModulesWithVersionGreaterThanLatestInstalled)); + afterEach(tearDown); + + it("should be emitted without unstable modules", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptionsWithVersionGreaterThanLatestInstalled); + done(err); + }); + }); + }); + + describe("if outdated modules were found with unstable modules", function () { + beforeEach(setupOutdatedModules(outdatedModulesUnstable)); + afterEach(tearDown); + + it("should be emitted without unstable modules", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptionsUnstable); + done(err); + }); + }); + }); + + describe("if outdated modules with git submodules were found", function () { + beforeEach(setupOutdatedModules(outdatedModulesWithGitDependencies)); + afterEach(tearDown); + + it("should be emitted without git submodules", function (done) { + var onOutdated = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("outdated", onOutdated); + } + }, function (err) { + expect(onOutdated).to.have.been.calledOnce; + expect(onOutdated).to.have.been.calledWithExactly(expectedOptions); + done(err); + }); + }); + }); + }); + + describe("updating", function () { + describe("if outdated modules were found", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted with latest version to install", function (done) { + var onUpdating = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("updating", onUpdating); + } + }, function (err) { + expect(onUpdating).to.have.been.calledOnce; + expect(onUpdating).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatest); + done(err); + }); + }); + + it("should be emitted with wanted version to install", function (done) { + var onUpdating = sinon.spy(); + + run({ + cwd: process.cwd(), + wanted: true, + reporter: function (emitter) { + emitter.on("updating", onUpdating); + } + }, function (err) { + expect(onUpdating).to.have.been.calledOnce; + expect(onUpdating).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountWanted); + done(err); + }); + }); + + it("should be abort with specified registry since yarn does not support it yet", function (done) { + function runIt() { + run({ + cwd: process.cwd(), + wanted: true, + registry: "https://custom.npm.registry" + }); + } + expect(runIt).to.throw(/`yarn add` does not support custom registries yet. Please use a .npmrc file to achieve this./); + done(); + }); + }); + + describe("if no outdated modules were found", function () { + beforeEach(setupOutdatedModules(noOutdatedModules)); + afterEach(tearDown); + + it("should not be emitted", function (done) { + var onUpdating = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("updating", onUpdating); + } + }, function (err) { + expect(onUpdating).to.not.have.been.called; + done(err); + }); + }); + }); + }); + + describe("testing", function () { + describe("if outdated modules were found", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onTesting = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("testing", onTesting); + } + }, function (err) { + expect(onTesting).to.have.been.calledOnce; + expect(onTesting).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatest); + done(err); + }); + }); + }); + }); + + describe("testing", function () { + describe("if custom test command is given", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted with correct command", function (done) { + var onTesting = sinon.spy(); + + run({ + cwd: process.cwd(), + testCmd: "yarn run test", + reporter: function (emitter) { + emitter.on("testing", onTesting); + } + }, function (err) { + expect(onTesting).to.have.been.calledOnce; + expect(onTesting).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatestAndCustomTestCmd); + done(err); + }); + }); + }); + }); + + describe("rollback", function () { + describe("if tests are failing", function () { + beforeEach(setupOutdatedModules(outdatedModules, false)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onRollback = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("rollback", onRollback); + } + }, function (err) { + expect(onRollback).to.have.been.calledOnce; + expect(onRollback).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatest); + done(err); + }); + }); + }); + + describe("if tests are passing", function () { + beforeEach(setupOutdatedModules(outdatedModules, true)); + afterEach(tearDown); + + it("should not be emitted", function (done) { + var onRollback = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("rollback", onRollback); + } + }, function (err) { + expect(onRollback).to.not.have.been.called; + done(err); + }); + }); + }); + }); + + describe("rollbackDone", function () { + describe("if outdated modules were found", function () { + beforeEach(setupOutdatedModules(outdatedModules, false)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onRollbackDone = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("rollbackDone", onRollbackDone); + } + }, function (err) { + expect(onRollbackDone).to.have.been.calledOnce; + expect(onRollbackDone).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatest); + done(err); + }); + }); + }); + }); + + describe("testStdout", function () { + describe("if --test-stdout is set and update fails", function () { + beforeEach(setupOutdatedModules(outdatedModules, false)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onTestStdout = sinon.spy(); + + run({ + cwd: process.cwd(), + testStdout: true, + reporter: function (emitter) { + emitter.on("testStdout", onTestStdout); + } + }, function (err) { + expect(onTestStdout).to.have.been.calledOnce; + expect(onTestStdout).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatestAndTestErrors); + done(err); + }); + }); + }); + }); + + describe("updatingDone", function () { + describe("if tests are passing", function () { + beforeEach(setupOutdatedModules(outdatedModules, true)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onUpdatingDone = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("updatingDone", onUpdatingDone); + } + }, function (err) { + expect(onUpdatingDone).to.have.been.calledOnce; + expect(onUpdatingDone).to.have.been.calledWithExactly(expectedOptionsWithCurrentCountLatest); + done(err); + }); + }); + }); + describe("if tests are failing", function () { + beforeEach(setupOutdatedModules(outdatedModules, false)); + afterEach(tearDown); + + it("should not be emitted", function (done) { + var onUpdatingDone = sinon.spy(); + + run({ + cwd: process.cwd(), + reporter: function (emitter) { + emitter.on("updatingDone", onUpdatingDone); + } + }, function (err) { + expect(onUpdatingDone).to.not.have.been.called; + done(err); + }); + }); + }); + }); + + describe("finished", function () { + describe("if outdated modules were found", function () { + beforeEach(setupOutdatedModules(outdatedModules)); + afterEach(tearDown); + + it("should be emitted", function (done) { + var onFinished = sinon.spy(); + + run({ + cwd: process.cwd(), + testStdout: true, + reporter: function (emitter) { + emitter.on("finished", onFinished); + } + }, function (err) { + expect(onFinished).to.have.been.calledOnce; + expect(onFinished).to.have.been.calledWithExactly(); + done(err); + }); + }); + }); + }); + }); +}); diff --git a/test/run.js b/test/run.js index f45d52f..1846132 100644 --- a/test/run.js +++ b/test/run.js @@ -278,6 +278,22 @@ var expectedOptionsWithCurrentCountWantedAndSpecifiedRegistry = { testCmd: "npm test", installCmd: "npm i --registry https://custom.npm.registry" }; +var expectedOptionsWithSaveExact = { + current: 1, + total: 1, + info: { + current: "0.1.4", + wanted: "1.1.5", + latest: "2.0.0", + location: "unicons", + type: "dependencies", + name: "unicons", + saveCmd: "--save", + updateTo: "2.0.0" + }, + testCmd: "npm test", + installCmd: "npm i --save-exact" +}; function tearDown() { childProcess.exec = execBackup; @@ -304,7 +320,7 @@ function setupOutdatedModules(obj, testsExpectToPass) { chai.use(sinonChai); -describe("run()", function () { +describe("npm run()", function () { it("should throw an error, if no options set", function () { expect(run).to.throw(Error); }); @@ -325,6 +341,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("init", onInit); } @@ -345,6 +362,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("noop", onNoop); } @@ -365,6 +383,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("noop", onNoop); } @@ -385,6 +404,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("modulesMissing", onModulesMissing); } @@ -410,6 +430,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("outdated", onOutdated); } @@ -430,6 +451,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, exclude: "servus.js", reporter: function (emitter) { emitter.on("outdated", onOutdated); @@ -451,6 +473,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, exclude: "asdf, servus.js", reporter: function (emitter) { emitter.on("outdated", onOutdated); @@ -472,6 +495,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("outdated", onOutdated); } @@ -492,6 +516,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("outdated", onOutdated); } @@ -512,6 +537,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("outdated", onOutdated); } @@ -534,6 +560,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("updating", onUpdating); } @@ -549,6 +576,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, wanted: true, reporter: function (emitter) { emitter.on("updating", onUpdating); @@ -565,6 +593,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, wanted: true, registry: "https://custom.npm.registry", reporter: function (emitter) { @@ -576,6 +605,23 @@ describe("run()", function () { done(err); }); }); + + it("should be emitted with save exact param", function (done) { + var onUpdating = sinon.spy(); + + run({ + cwd: process.cwd(), + forceNpm: true, + saveExact: true, + reporter: function (emitter) { + emitter.on("updating", onUpdating); + } + }, function (err) { + expect(onUpdating).to.have.been.calledOnce; + expect(onUpdating).to.have.been.calledWithExactly(expectedOptionsWithSaveExact); + done(err); + }); + }); }); describe("if no outdated modules were found", function () { @@ -587,6 +633,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("updating", onUpdating); } @@ -608,6 +655,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("testing", onTesting); } @@ -630,6 +678,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, testCmd: "npm run test", reporter: function (emitter) { emitter.on("testing", onTesting); @@ -653,6 +702,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("rollback", onRollback); } @@ -673,6 +723,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("rollback", onRollback); } @@ -694,6 +745,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("rollbackDone", onRollbackDone); } @@ -716,6 +768,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, testStdout: true, reporter: function (emitter) { emitter.on("testStdout", onTestStdout); @@ -739,6 +792,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("updatingDone", onUpdatingDone); } @@ -758,6 +812,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, reporter: function (emitter) { emitter.on("updatingDone", onUpdatingDone); } @@ -779,6 +834,7 @@ describe("run()", function () { run({ cwd: process.cwd(), + forceNpm: true, testStdout: true, reporter: function (emitter) { emitter.on("finished", onFinished);