diff --git a/package-lock.json b/package-lock.json index 65dd57c5..ee4c5ce7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,10 +55,10 @@ "nock": "13.2.1", "nyc": "15.1.0", "p-retry": "4.6.1", - "proxyquire": "2.1.3", "sinon": "12.0.1", "stream-buffers": "3.0.2", "tempy": "1.0.1", + "testdouble": "3.16.6", "xo": "0.32.1" }, "engines": { @@ -5912,19 +5912,6 @@ "node": ">=8" } }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -8096,15 +8083,6 @@ "obj-props": "^1.0.0" } }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -8169,6 +8147,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -9244,12 +9231,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9490,12 +9471,6 @@ "node": ">=0.10.0" } }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13226,17 +13201,6 @@ "node": ">=4" } }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -13334,6 +13298,20 @@ } ] }, + "node_modules/quibble": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.6.14.tgz", + "integrity": "sha512-r5noQhWx61qMOjaMQ48ePOKc9MKXzXFKUNj4S7/wIB9rzht3yyyf/Ms3BhXEVEPJtUvTNNnQxnT/6sHzcbkRoA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21", + "resolve": "^1.20.0" + }, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, "node_modules/quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -14710,6 +14688,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object-es5": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz", + "integrity": "sha512-vE7Xdx9ylG4JI16zy7/ObKUB+MtxuMcWlj/WHHr3+yAlQoN6sst2stU9E+2Qs3OrlJw/Pf3loWxL1GauEHf6MA==", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -15109,6 +15100,21 @@ "node": ">=8" } }, + "node_modules/testdouble": { + "version": "3.16.6", + "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.16.6.tgz", + "integrity": "sha512-mijMgc9y7buK9IG9zSVhzlXsFMqWbLQHRei4SLX7F7K4Qtrcnglg6lIMTCmNs6RwDUyLGWtpIe+TzkugYHB+qA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15", + "quibble": "^0.6.7", + "stringify-object-es5": "^2.5.0", + "theredoc": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/text-extensions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", @@ -15123,6 +15129,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/theredoc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", + "integrity": "sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA==", + "dev": true + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -21467,16 +21479,6 @@ "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", "dev": true }, - "fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -23133,12 +23135,6 @@ "obj-props": "^1.0.0" } }, - "is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -23185,6 +23181,12 @@ "has-symbols": "^1.0.1" } }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true + }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -24011,12 +24013,6 @@ "yargs-parser": "^20.2.3" } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -24206,12 +24202,6 @@ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==" }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -26869,17 +26859,6 @@ "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", "dev": true }, - "proxyquire": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -26948,6 +26927,16 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "quibble": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.6.14.tgz", + "integrity": "sha512-r5noQhWx61qMOjaMQ48ePOKc9MKXzXFKUNj4S7/wIB9rzht3yyyf/Ms3BhXEVEPJtUvTNNnQxnT/6sHzcbkRoA==", + "dev": true, + "requires": { + "lodash": "^4.17.21", + "resolve": "^1.20.0" + } + }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -28062,6 +28051,16 @@ "define-properties": "^1.1.3" } }, + "stringify-object-es5": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz", + "integrity": "sha512-vE7Xdx9ylG4JI16zy7/ObKUB+MtxuMcWlj/WHHr3+yAlQoN6sst2stU9E+2Qs3OrlJw/Pf3loWxL1GauEHf6MA==", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0", + "is-regexp": "^1.0.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -28350,6 +28349,18 @@ "minimatch": "^3.0.4" } }, + "testdouble": { + "version": "3.16.6", + "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.16.6.tgz", + "integrity": "sha512-mijMgc9y7buK9IG9zSVhzlXsFMqWbLQHRei4SLX7F7K4Qtrcnglg6lIMTCmNs6RwDUyLGWtpIe+TzkugYHB+qA==", + "dev": true, + "requires": { + "lodash": "^4.17.15", + "quibble": "^0.6.7", + "stringify-object-es5": "^2.5.0", + "theredoc": "^1.0.0" + } + }, "text-extensions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", @@ -28361,6 +28372,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "theredoc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", + "integrity": "sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA==", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/package.json b/package.json index e2902c3a..736669c6 100644 --- a/package.json +++ b/package.json @@ -63,10 +63,10 @@ "nock": "13.2.1", "nyc": "15.1.0", "p-retry": "4.6.1", - "proxyquire": "2.1.3", "sinon": "12.0.1", "stream-buffers": "3.0.2", "tempy": "1.0.1", + "testdouble": "3.16.6", "xo": "0.32.1" }, "engines": { diff --git a/test/branches/branches.test.js b/test/branches/branches.test.js index b193514a..26612352 100644 --- a/test/branches/branches.test.js +++ b/test/branches/branches.test.js @@ -1,7 +1,7 @@ const test = require('ava'); const {union} = require('lodash'); const semver = require('semver'); -const proxyquire = require('proxyquire'); +const td = require('testdouble'); const getBranch = (branches, branch) => branches.find(({name}) => name === branch); const release = (branches, name, version) => getBranch(branches, name).tags.push({version}); @@ -22,7 +22,9 @@ test('Enforce ranges with branching release workflow', async (t) => { {name: 'beta', prerelease: true, tags: []}, {name: 'alpha', prerelease: true, tags: []}, ]; - const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []}); + td.replace('../../lib/branches/get-tags', () => branches); + td.replace('../../lib/branches/expand', () => []); + const getBranches = require('../../lib/branches'); let result = (await getBranches('repositoryUrl', 'master', {options: {branches}})).map(({name, range}) => ({ name, @@ -199,7 +201,9 @@ test('Throw SemanticReleaseError for invalid configurations', async (t) => { {name: 'alpha', prerelease: 'alpha', tags: []}, {name: 'preview', prerelease: 'alpha', tags: []}, ]; - const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []}); + td.replace('../../lib/branches/get-tags', () => branches); + td.replace('../../lib/branches/expand', () => []); + const getBranches = require('../../lib/branches'); const errors = [...(await t.throwsAsync(getBranches('repositoryUrl', 'master', {options: {branches}})))]; t.is(errors[0].name, 'SemanticReleaseError'); @@ -229,7 +233,9 @@ test('Throw a SemanticReleaseError if there is duplicate branches', async (t) => {name: 'master', tags: []}, {name: 'master', tags: []}, ]; - const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []}); + td.replace('../../lib/branches/get-tags', () => branches); + td.replace('../../lib/branches/expand', () => []); + const getBranches = require('../../lib/branches'); const errors = [...(await t.throwsAsync(getBranches('repositoryUrl', 'master', {options: {branches}})))]; @@ -244,7 +250,9 @@ test('Throw a SemanticReleaseError for each invalid branch name', async (t) => { {name: '~master', tags: []}, {name: '^master', tags: []}, ]; - const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []}); + td.replace('../../lib/branches/get-tags', () => branches); + td.replace('../../lib/branches/expand', () => []); + const getBranches = require('../../lib/branches'); const errors = [...(await t.throwsAsync(getBranches('repositoryUrl', 'master', {options: {branches}})))]; diff --git a/test/cli.test.js b/test/cli.test.js index 90715a37..d60743d6 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -1,9 +1,12 @@ const test = require('ava'); const {escapeRegExp} = require('lodash'); -const proxyquire = require('proxyquire').noPreserveCache(); +const td = require('testdouble'); const {stub} = require('sinon'); const {SECRET_REPLACEMENT} = require('../lib/definitions/constants'); +let previousArgv; +let previousEnv; + test.beforeEach((t) => { t.context.logs = ''; t.context.errors = ''; @@ -13,11 +16,17 @@ test.beforeEach((t) => { t.context.stderr = stub(process.stderr, 'write').callsFake((value) => { t.context.errors += value.toString(); }); + + previousArgv = process.argv; + previousEnv = process.env; }); test.afterEach.always((t) => { t.context.stdout.restore(); t.context.stderr.restore(); + + process.argv = previousArgv; + process.env = previousEnv; }); test.serial('Pass options to semantic-release API', async (t) => { @@ -63,7 +72,9 @@ test.serial('Pass options to semantic-release API', async (t) => { '--debug', '-d', ]; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -105,7 +116,9 @@ test.serial('Pass options to semantic-release API with alias arguments', async ( 'config2', '--dry-run', ]; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -122,7 +135,9 @@ test.serial('Pass options to semantic-release API with alias arguments', async ( test.serial('Pass unknown options to semantic-release API', async (t) => { const run = stub().resolves(true); const argv = ['', '', '--bool', '--first-option', 'value1', '--second-option', 'value2', '--second-option', 'value3']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -136,7 +151,9 @@ test.serial('Pass unknown options to semantic-release API', async (t) => { test.serial('Pass empty Array to semantic-release API for list option set to "false"', async (t) => { const run = stub().resolves(true); const argv = ['', '', '--publish', 'false']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -148,7 +165,9 @@ test.serial('Pass empty Array to semantic-release API for list option set to "fa test.serial('Do not set properties in option for which arg is not in command line', async (t) => { const run = stub().resolves(true); const argv = ['', '', '-b', 'master']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); await cli(); @@ -165,7 +184,9 @@ test.serial('Do not set properties in option for which arg is not in command lin test.serial('Display help', async (t) => { const run = stub().resolves(true); const argv = ['', '', '--help']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -176,7 +197,9 @@ test.serial('Display help', async (t) => { test.serial('Return error exitCode and prints help if called with a command', async (t) => { const run = stub().resolves(true); const argv = ['', '', 'pre']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -188,7 +211,9 @@ test.serial('Return error exitCode and prints help if called with a command', as test.serial('Return error exitCode if multiple plugin are set for single plugin', async (t) => { const run = stub().resolves(true); const argv = ['', '', '--analyze-commits', 'analyze1', 'analyze2']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -200,7 +225,9 @@ test.serial('Return error exitCode if multiple plugin are set for single plugin' test.serial('Return error exitCode if semantic-release throw error', async (t) => { const run = stub().rejects(new Error('semantic-release error')); const argv = ['', '']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); + td.replace('..', run); + process.argv = argv; + const cli = require('../cli'); const exitCode = await cli(); @@ -212,7 +239,10 @@ test.serial('Hide sensitive environment variable values from the logs', async (t const env = {MY_TOKEN: 'secret token'}; const run = stub().rejects(new Error(`Throw error: Exposing token ${env.MY_TOKEN}`)); const argv = ['', '']; - const cli = proxyquire('../cli', {'.': run, process: {...process, argv, env: {...process.env, ...env}}}); + td.replace('..', run); + process.argv = argv; + process.env = {...process.env, ...env}; + const cli = require('../cli'); const exitCode = await cli(); diff --git a/test/get-config.test.js b/test/get-config.test.js index 28a9ec62..76eab49e 100644 --- a/test/get-config.test.js +++ b/test/get-config.test.js @@ -3,7 +3,7 @@ const {format} = require('util'); const test = require('ava'); const {writeFile, outputJson} = require('fs-extra'); const {omit} = require('lodash'); -const proxyquire = require('proxyquire'); +const td = require('testdouble'); const {stub} = require('sinon'); const yaml = require('js-yaml'); const {gitRepo, gitTagVersion, gitCommits, gitShallowClone, gitAddConfig} = require('./helpers/git-utils'); @@ -17,7 +17,8 @@ const DEFAULT_PLUGINS = [ test.beforeEach((t) => { t.context.plugins = stub().returns({}); - t.context.getConfig = proxyquire('../lib/get-config', {'./plugins': t.context.plugins}); + td.replace('../lib/plugins', t.context.plugins); + t.context.getConfig = require('../lib/get-config'); }); test('Default values, reading repositoryUrl from package.json', async (t) => { diff --git a/test/index.test.js b/test/index.test.js index 2f1b09b8..6d38b489 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,6 +1,6 @@ const test = require('ava'); const {escapeRegExp, isString, sortBy, omit} = require('lodash'); -const proxyquire = require('proxyquire'); +const td = require('testdouble'); const {spy, stub} = require('sinon'); const {WritableStreamBuffer} = require('stream-buffers'); const AggregateError = require('aggregate-error'); @@ -23,7 +23,6 @@ const { gitGetNote, } = require('./helpers/git-utils'); -const requireNoCache = proxyquire.noPreserveCache(); const pluginNoop = require.resolve('./fixtures/plugin-noop'); test.beforeEach((t) => { @@ -144,10 +143,9 @@ test('Plugins are called with expected values', async (t) => { {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: pluginNoop}, ]; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => envCi, - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => envCi); + const semanticRelease = require('..'); const result = await semanticRelease(options, { cwd, env, @@ -420,10 +418,9 @@ test('Use custom tag format', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -479,10 +476,9 @@ test('Use new gitHead, and recreate release notes if a prepare plugin create a c fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { @@ -546,10 +542,9 @@ test('Make a new release when a commit is forward-ported to an upper branch', as success, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})); t.is(addChannel.callCount, 0); @@ -581,10 +576,9 @@ test('Publish a pre-release version', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'beta', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'beta', isPr: false})); + const semanticRelease = require('..'); let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); t.is(releases.length, 1); @@ -634,10 +628,9 @@ test('Publish releases from different branch on the same channel', async (t) => fail: stub().resolves(), }; - let semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'next', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'next', isPr: false})); + let semanticRelease = require('..'); let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); t.is(releases.length, 1); @@ -660,10 +653,9 @@ test('Publish releases from different branch on the same channel', async (t) => await merge('next', {cwd}); await gitPush('origin', 'master', {cwd}); - semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + semanticRelease = require('..'); t.falsy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})); t.is(addChannel.callCount, 0); @@ -694,10 +686,9 @@ test('Publish pre-releases the same channel as regular releases', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'beta', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'beta', isPr: false})); + const semanticRelease = require('..'); let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); t.is(releases.length, 1); @@ -760,10 +751,9 @@ test('Do not add pre-releases to a different channel', async (t) => { success, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})); t.is(addChannel.callCount, 0); @@ -829,10 +819,9 @@ async function addChannelMacro(t, mergeFunction) { gitHead: commits[2].hash, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const result = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); t.deepEqual(result.releases, [ @@ -896,10 +885,9 @@ test('Call all "success" plugins even if one errors out', async (t) => { success: [success1, success2], }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -941,10 +929,9 @@ test('Log all "verifyConditions" errors', async (t) => { fail, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const errors = [ ...(await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -986,10 +973,9 @@ test('Log all "verifyRelease" errors', async (t) => { fail, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const errors = [ ...(await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -1040,10 +1026,9 @@ test('Dry-run skips addChannel, prepare, publish and success', async (t) => { success, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -1093,10 +1078,9 @@ test('Dry-run skips fail', async (t) => { fail, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const errors = [ ...(await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -1153,10 +1137,9 @@ test('Force a dry-run if not on a CI and "noCi" is not explicitly set', async (t fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: false, branch: 'master'}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: false, branch: 'master'})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -1203,10 +1186,9 @@ test('Dry-run does not print changelog if "generateNotes" return "undefined"', a success: false, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -1262,10 +1244,9 @@ test('Allow local releases with "noCi" option', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: false, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: false, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -1332,10 +1313,9 @@ test('Accept "undefined" value returned by "generateNotes" and "false" by "publi fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, @@ -1361,10 +1341,9 @@ test('Returns false if triggered by a PR', async (t) => { // Create a git repository, set the current working directory at the root of the repo const {cwd, repositoryUrl} = await gitRepo(true); - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', prBranch: 'patch-1', isPr: true}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', prBranch: 'patch-1', isPr: true})); + const semanticRelease = require('..'); t.false( await semanticRelease( @@ -1414,10 +1393,9 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren success, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: '1.x', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: '1.x', isPr: false})); + const semanticRelease = require('..'); const error = await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}) @@ -1466,10 +1444,9 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren success, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const error = await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}) @@ -1526,10 +1503,9 @@ test('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a ma fail, }; - const semanticRelease = proxyquire('..', { - './lib/logger': t.context.logger, - 'env-ci': () => ({isCi: true, branch: '1.1.x', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: '1.1.x', isPr: false})); + const semanticRelease = require('..'); const errors = [ ...(await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}) @@ -1563,10 +1539,9 @@ test('Returns false value if triggered on an outdated clone', async (t) => { await gitCommits(['Third'], {cwd}); await gitPush(repositoryUrl, 'master', {cwd}); - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.false( await semanticRelease( @@ -1596,10 +1571,9 @@ test('Returns false if not running from the configured branch', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'other-branch', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'other-branch', isPr: false})); + const semanticRelease = require('..'); t.false( await semanticRelease(options, { @@ -1641,10 +1615,9 @@ test('Returns false if there is no relevant changes', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.false( await semanticRelease(options, { @@ -1697,10 +1670,9 @@ test('Exclude commits with [skip release] or [release skip] from analysis', asyn fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await semanticRelease(options, { cwd, env: {}, @@ -1725,10 +1697,9 @@ test('Log both plugins errors and errors thrown by "fail" plugin', async (t) => verifyConditions: stub().rejects(pluginError), fail: [stub().rejects(failError1), stub().rejects(failError2)], }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -1750,10 +1721,9 @@ test('Call "fail" only if a plugin returns a SemanticReleaseError', async (t) => verifyConditions: stub().rejects(pluginError), fail, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -1767,10 +1737,9 @@ test('Throw SemanticReleaseError if repositoryUrl is not set and cannot be found // Create a git repository, set the current working directory at the root of the repo const {cwd} = await gitRepo(); - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const errors = [ ...(await t.throwsAsync( semanticRelease({}, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) @@ -1807,10 +1776,9 @@ test('Throw an Error if plugin returns an unexpected value', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const error = await t.throwsAsync( semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}), {instanceOf: SemanticReleaseError} @@ -1837,10 +1805,9 @@ test('Hide sensitive information passed to "fail" plugin', async (t) => { fail, }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await t.throwsAsync( semanticRelease(options, {cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}) ); @@ -1882,10 +1849,9 @@ test('Hide sensitive information passed to "success" plugin', async (t) => { fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); await semanticRelease(options, {cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}); const release = success.args[0][1].releases[0]; @@ -1932,10 +1898,9 @@ test('Get all commits including the ones not in the shallow clone', async (t) => fail: stub().resolves(), }; - const semanticRelease = requireNoCache('..', { - './lib/get-logger': () => t.context.logger, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/get-logger', () => t.context.logger); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); t.truthy( await semanticRelease(options, { cwd, diff --git a/test/integration.test.js b/test/integration.test.js index 6ffc91dd..c3cb7ff3 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,6 +1,6 @@ const path = require('path'); const test = require('ava'); -const proxyquire = require('proxyquire'); +const td = require('testdouble'); const {escapeRegExp} = require('lodash'); const {writeJson, readJson} = require('fs-extra'); const execa = require('execa'); @@ -26,8 +26,6 @@ const npmRegistry = require('./helpers/npm-registry'); /* eslint camelcase: ["error", {properties: "never"}] */ -const requireNoCache = proxyquire.noPreserveCache(); - // Environment variables used with semantic-release cli (similar to what a user would setup) const {GITHUB_ACTION, GITHUB_TOKEN, ...processEnvWithoutGitHubActionsVariables} = process.env; const env = { @@ -509,10 +507,9 @@ test('Pass options via CLI arguments', async (t) => { }); test('Run via JS API', async (t) => { - const semanticRelease = requireNoCache('..', { - './lib/logger': {log: () => {}, error: () => {}, stdout: () => {}}, - 'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), - }); + td.replace('../lib/logger', {log: () => {}, error: () => {}, stdout: () => {}}); + td.replace('env-ci', () => ({isCi: true, branch: 'master', isPr: false})); + const semanticRelease = require('..'); const packageName = 'test-js-api'; const owner = 'git'; // Create a git repository, set the current working directory at the root of the repo