From ab7a4281028a46f5acc6aecda927cc6d39620e45 Mon Sep 17 00:00:00 2001 From: Gregor Martynus <39992+gr2m@users.noreply.github.com> Date: Fri, 30 Jul 2021 13:52:30 -0700 Subject: [PATCH] WIP esm - adapt sinon --- test/cli.test.js | 26 +-- test/get-commits.test.js | 6 +- test/get-config.test.js | 4 +- test/get-next-version.test.js | 4 +- test/index.test.js | 408 ++++++++++++++++----------------- test/plugins/normalize.test.js | 26 +-- test/plugins/pipeline.test.js | 80 +++---- test/plugins/plugins.test.js | 16 +- 8 files changed, 285 insertions(+), 285 deletions(-) diff --git a/test/cli.test.js b/test/cli.test.js index b3ff73f5..c5067375 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -1,16 +1,16 @@ import test from 'ava'; import {escapeRegExp} from 'lodash'; const proxyquire = require('proxyquire').noPreserveCache(); -import {stub} from 'sinon'; +import sinon from 'sinon'; import {SECRET_REPLACEMENT} from '../lib/definitions/constants.js'; test.beforeEach((t) => { t.context.logs = ''; t.context.errors = ''; - t.context.stdout = stub(process.stdout, 'write').callsFake((value) => { + t.context.stdout = sinon.stubprocess.stdout, 'write').callsFake((value) => { t.context.logs += value.toString(); }); - t.context.stderr = stub(process.stderr, 'write').callsFake((value) => { + t.context.stderr = sinon.stubprocess.stderr, 'write').callsFake((value) => { t.context.errors += value.toString(); }); }); @@ -21,7 +21,7 @@ test.afterEach.always((t) => { }); test.serial('Pass options to semantic-release API', async (t) => { - const run = stub().resolves(true); + const run = sinon.stub).resolves(true); const argv = [ '', '', @@ -87,7 +87,7 @@ test.serial('Pass options to semantic-release API', async (t) => { }); test.serial('Pass options to semantic-release API with alias arguments', async (t) => { - const run = stub().resolves(true); + const run = sinon.stub).resolves(true); const argv = [ '', '', @@ -120,7 +120,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', '--bool', '--first-option', 'value1', '--second-option', 'value2', '--second-option', 'value3']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -134,7 +134,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', '--publish', 'false']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -146,7 +146,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', '-b', 'master']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -163,7 +163,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', '--help']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -174,7 +174,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', 'pre']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -186,7 +186,7 @@ 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 run = sinon.stub).resolves(true); const argv = ['', '', '--analyze-commits', 'analyze1', 'analyze2']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -198,7 +198,7 @@ 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 run = sinon.stub).rejects(new Error('semantic-release error')); const argv = ['', '']; const cli = proxyquire('../cli', {'.': run, process: {...process, argv}}); @@ -210,7 +210,7 @@ test.serial('Return error exitCode if semantic-release throw error', async (t) = 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 run = sinon.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}}}); diff --git a/test/get-commits.test.js b/test/get-commits.test.js index a4445c4f..da9e2efe 100644 --- a/test/get-commits.test.js +++ b/test/get-commits.test.js @@ -1,12 +1,12 @@ import test from 'ava'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import getCommits from '../lib/get-commits.js'; import {gitRepo, gitCommits, gitDetachedHead} from './helpers/git-utils.js'; test.beforeEach((t) => { // Stub the logger functions - t.context.log = stub(); - t.context.error = stub(); + t.context.log = sinon.stub(); + t.context.error = sinon.stub(); t.context.logger = {log: t.context.log, error: t.context.error}; }); diff --git a/test/get-config.test.js b/test/get-config.test.js index 08b242ee..05fb28e6 100644 --- a/test/get-config.test.js +++ b/test/get-config.test.js @@ -4,7 +4,7 @@ import test from 'ava'; import {writeFile, outputJson} from 'fs-extra'; import {omit} from 'lodash'; import proxyquire from 'proxyquire'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import yaml from 'js-yaml'; import {gitRepo, gitTagVersion, gitCommits, gitShallowClone, gitAddConfig} from './helpers/git-utils.js'; @@ -16,7 +16,7 @@ const DEFAULT_PLUGINS = [ ]; test.beforeEach((t) => { - t.context.plugins = stub().returns({}); + t.context.plugins = sinon.stub).returns({}); t.context.getConfig = proxyquire('../lib/get-config', {'./plugins': t.context.plugins}); }); diff --git a/test/get-next-version.test.js b/test/get-next-version.test.js index 58ddff29..e2eb4a27 100644 --- a/test/get-next-version.test.js +++ b/test/get-next-version.test.js @@ -1,10 +1,10 @@ import test from 'ava'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import getNextVersion from '../lib/get-next-version.js'; test.beforeEach((t) => { // Stub the logger functions - t.context.log = stub(); + t.context.log = sinon.stub); t.context.logger = {log: t.context.log}; }); diff --git a/test/index.test.js b/test/index.test.js index 86c8f712..f249eb21 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,7 +1,7 @@ import test from 'ava'; import {escapeRegExp, isString, sortBy, omit} from 'lodash'; import proxyquire from 'proxyquire'; -import {spy, stub} from 'sinon'; +import sinon from 'sinon'; import {WritableStreamBuffer} from 'stream-buffers'; import AggregateError from 'aggregate-error'; import SemanticReleaseError from '@semantic-release/error'; @@ -29,10 +29,10 @@ const pluginNoop = require.resolve('./fixtures/plugin-noop'); test.beforeEach((t) => { // Stub the logger functions - t.context.log = spy(); - t.context.error = spy(); - t.context.success = spy(); - t.context.warn = spy(); + t.context.log = sinon.spy(); + t.context.error = sinon.spy(); + t.context.success = sinon.spy(); + t.context.warn = sinon.spy(); t.context.logger = { log: t.context.log, error: t.context.error, @@ -74,19 +74,19 @@ test('Plugins are called with expected values', async (t) => { const notes1 = 'Release notes 1'; const notes2 = 'Release notes 2'; const notes3 = 'Release notes 3'; - const verifyConditions1 = stub().resolves(); - const verifyConditions2 = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes1 = stub().resolves(notes1); - const generateNotes2 = stub().resolves(notes2); - const generateNotes3 = stub().resolves(notes3); + const verifyConditions1 = sinon.stub().resolves(); + const verifyConditions2 = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const verifyRelease = sinon.stub().resolves(); + const generateNotes1 = sinon.stub().resolves(notes1); + const generateNotes2 = sinon.stub().resolves(notes2); + const generateNotes3 = sinon.stub().resolves(notes3); const release1 = {name: 'Release 1', url: 'https://release1.com'}; const release2 = {name: 'Release 2', url: 'https://release2.com'}; - const addChannel = stub().resolves(release1); - const prepare = stub().resolves(); - const publish = stub().resolves(release2); - const success = stub().resolves(); + const addChannel = sinon.stub().resolves(release1); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(release2); + const success = sinon.stub().resolves(); const env = {}; const config = { branches: [{name: 'master'}, {name: 'next'}], @@ -409,15 +409,15 @@ test('Use custom tag format', async (t) => { const config = {branches: 'master', repositoryUrl, globalOpt: 'global', tagFormat: `test-\${version}`}; const options = { ...config, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(nextRelease.type), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(notes), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + verifyConditions: sinon.stub().resolves(), + analyzeCommits: sinon.stub().resolves(nextRelease.type), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(notes), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -459,24 +459,24 @@ test('Use new gitHead, and recreate release notes if a prepare plugin create a c }; const notes = 'Release notes'; - const generateNotes = stub().resolves(notes); - const prepare1 = stub().callsFake(async () => { + const generateNotes = sinon.stub().resolves(notes); + const prepare1 = sinon.stub().callsFake(async () => { commits = (await gitCommits(['Third'], {cwd})).concat(commits); }); - const prepare2 = stub().resolves(); - const publish = stub().resolves(); + const prepare2 = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); const options = { branches: ['master'], repositoryUrl, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(nextRelease.type), - verifyRelease: stub().resolves(), + verifyConditions: sinon.stub().resolves(), + analyzeCommits: sinon.stub().resolves(nextRelease.type), + verifyRelease: sinon.stub().resolves(), generateNotes, - addChannel: stub().resolves(), + addChannel: sinon.stub().resolves(), prepare: [prepare1, prepare2], publish, - success: stub().resolves(), - fail: stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -528,12 +528,12 @@ test('Make a new release when a commit is forward-ported to an upper branch', as await merge('1.0.x', {cwd}); await gitPush('origin', 'master', {cwd}); - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const addChannel = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const config = {branches: [{name: '1.0.x'}, {name: 'master'}], repositoryUrl, tagFormat: `v\${version}`}; const options = { @@ -571,14 +571,14 @@ test('Publish a pre-release version', async (t) => { const config = {branches: ['master', {name: 'beta', prerelease: true}], repositoryUrl}; const options = { ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(''), + verifyConditions: sinon.stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(''), addChannel: false, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -621,17 +621,17 @@ test('Publish releases from different branch on the same channel', async (t) => branches: ['master', {name: 'next', channel: false}, {name: 'next-major', channel: false}], repositoryUrl, }; - const addChannel = stub().resolves({}); + const addChannel = sinon.stub().resolves({}); const options = { ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(''), + verifyConditions: sinon.stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(''), addChannel, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; let semanticRelease = requireNoCache('..', { @@ -684,14 +684,14 @@ test('Publish pre-releases the same channel as regular releases', async (t) => { }; const options = { ...config, - verifyConditions: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(''), + verifyConditions: sinon.stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(''), addChannel: false, - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -734,14 +734,14 @@ test('Do not add pre-releases to a different channel', async (t) => { await merge('beta', {cwd}); await gitPush('origin', 'master', {cwd}); - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves('Release notes'); + const verifyConditions = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves('Release notes'); const release1 = {name: 'Release 1', url: 'https://release1.com'}; - const addChannel = stub().resolves(release1); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const addChannel = sinon.stub().resolves(release1); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const config = { branches: [{name: 'master'}, {name: 'beta', prerelease: 'beta'}], @@ -792,15 +792,15 @@ async function addChannelMacro(t, mergeFunction) { await gitPush('origin', 'master', {cwd}); const notes = 'Release notes'; - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); + const verifyConditions = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(notes); const release1 = {name: 'Release 1', url: 'https://release1.com'}; - const addChannel1 = stub().resolves(release1); - const addChannel2 = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const addChannel1 = sinon.stub().resolves(release1); + const addChannel2 = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const config = { branches: [ @@ -871,14 +871,14 @@ test('Call all "success" plugins even if one errors out', async (t) => { channel: null, }; const notes = 'Release notes'; - const verifyConditions1 = stub().resolves(); - const verifyConditions2 = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const generateNotes = stub().resolves(notes); + const verifyConditions1 = sinon.stub().resolves(); + const verifyConditions2 = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const generateNotes = sinon.stub().resolves(notes); const release = {name: 'Release', url: 'https://release.com'}; - const publish = stub().resolves(release); - const success1 = stub().rejects(); - const success2 = stub().resolves(); + const publish = sinon.stub().resolves(release); + const success1 = sinon.stub().rejects(); + const success2 = sinon.stub().resolves(); const config = { branches: [{name: 'master'}], repositoryUrl, @@ -890,8 +890,8 @@ test('Call all "success" plugins even if one errors out', async (t) => { verifyConditions: [verifyConditions1, verifyConditions2], analyzeCommits, generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), publish, success: [success1, success2], }; @@ -927,12 +927,12 @@ test('Log all "verifyConditions" errors', async (t) => { const error1 = new Error('error 1'); const error2 = new SemanticReleaseError('error 2', 'ERR2'); const error3 = new SemanticReleaseError('error 3', 'ERR3'); - const fail = stub().resolves(); + const fail = sinon.stub().resolves(); const config = {branches: [{name: 'master'}], repositoryUrl, tagFormat: `v\${version}`}; const options = { ...config, plugins: false, - verifyConditions: [stub().rejects(new AggregateError([error1, error2])), stub().rejects(error3)], + verifyConditions: [sinon.stub().rejects(new AggregateError([error1, error2])), sinon.stub().rejects(error3)], fail, }; @@ -971,13 +971,13 @@ test('Log all "verifyRelease" errors', async (t) => { const error1 = new SemanticReleaseError('error 1', 'ERR1'); const error2 = new SemanticReleaseError('error 2', 'ERR2'); - const fail = stub().resolves(); + const fail = sinon.stub().resolves(); const config = {branches: [{name: 'master'}], repositoryUrl, tagFormat: `v\${version}`}; const options = { ...config, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves('major'), - verifyRelease: [stub().rejects(error1), stub().rejects(error2)], + verifyConditions: sinon.stub().resolves(), + analyzeCommits: sinon.stub().resolves('major'), + verifyRelease: [sinon.stub().rejects(error1), sinon.stub().rejects(error2)], fail, }; @@ -1012,14 +1012,14 @@ test('Dry-run skips addChannel, prepare, publish and success', async (t) => { await gitCheckout('next', true, {cwd}); await gitPush('origin', 'next', {cwd}); - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves('minor'); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves('minor'); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(); + const addChannel = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const options = { dryRun: true, @@ -1078,13 +1078,13 @@ test('Dry-run skips fail', async (t) => { const error1 = new SemanticReleaseError('error 1', 'ERR1'); const error2 = new SemanticReleaseError('error 2', 'ERR2'); - const fail = stub().resolves(); + const fail = sinon.stub().resolves(); const options = { dryRun: true, branches: ['master'], repositoryUrl, - verifyConditions: [stub().rejects(error1), stub().rejects(error2)], + verifyConditions: [sinon.stub().rejects(error1), sinon.stub().rejects(error2)], fail, }; @@ -1126,12 +1126,12 @@ test('Force a dry-run if not on a CI and "noCi" is not explicitly set', async (t }; const notes = 'Release notes'; - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(notes); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const options = { dryRun: false, @@ -1141,11 +1141,11 @@ test('Force a dry-run if not on a CI and "noCi" is not explicitly set', async (t analyzeCommits, verifyRelease, generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), publish, success, - fail: stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1182,8 +1182,8 @@ test('Dry-run does not print changelog if "generateNotes" return "undefined"', a await gitPush(repositoryUrl, 'master', {cwd}); const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead({cwd}), gitTag: 'v2.0.0'}; - const analyzeCommits = stub().resolves(nextRelease.type); - const generateNotes = stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const generateNotes = sinon.stub().resolves(); const options = { dryRun: true, @@ -1235,12 +1235,12 @@ test('Allow local releases with "noCi" option', async (t) => { }; const notes = 'Release notes'; - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(notes); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const options = { noCi: true, @@ -1250,11 +1250,11 @@ test('Allow local releases with "noCi" option', async (t) => { analyzeCommits, verifyRelease, generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), publish, success, - fail: stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1304,27 +1304,27 @@ test('Accept "undefined" value returned by "generateNotes" and "false" by "publi gitTag: 'v1.2.0', channel: null, }; - const analyzeCommits = stub().resolves(nextRelease.type); - const verifyRelease = stub().resolves(); - const generateNotes1 = stub().resolves(); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); + const verifyRelease = sinon.stub().resolves(); + const generateNotes1 = sinon.stub().resolves(); const notes2 = 'Release notes 2'; - const generateNotes2 = stub().resolves(notes2); - const publish = stub().resolves(false); - const addChannel = stub().resolves(false); - const success = stub().resolves(); + const generateNotes2 = sinon.stub().resolves(notes2); + const publish = sinon.stub().resolves(false); + const addChannel = sinon.stub().resolves(false); + const success = sinon.stub().resolves(); const options = { branches: ['master', 'next'], repositoryUrl, - verifyConditions: stub().resolves(), + verifyConditions: sinon.stub().resolves(), analyzeCommits, verifyRelease, generateNotes: [generateNotes1, generateNotes2], addChannel, - prepare: stub().resolves(), + prepare: sinon.stub().resolves(), publish, success, - fail: stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1387,12 +1387,12 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren await gitCommits(['feat: feature on maintenance version 1.x'], {cwd}); await gitPush('origin', 'master', {cwd}); - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const addChannel = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const config = { branches: [{name: '1.x'}, {name: 'master'}], @@ -1439,12 +1439,12 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren await gitCommits(['feat: new feature on master', 'fix: new fix on master'], {cwd}); await gitPush('origin', 'master', {cwd}); - const verifyConditions = stub().resolves(); - const verifyRelease = stub().resolves(); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const addChannel = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); const config = { branches: [{name: 'master'}, {name: 'next'}, {name: 'next-major'}], @@ -1497,15 +1497,15 @@ test('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a ma await gitPush('origin', '1.1.x', {cwd}); const notes = 'Release notes'; - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(notes); - const addChannel = stub().resolves(); - const prepare = stub().resolves(); - const publish = stub().resolves(); - const success = stub().resolves(); - const fail = stub().resolves(); + const verifyConditions = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(notes); + const addChannel = sinon.stub().resolves(); + const prepare = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); + const success = sinon.stub().resolves(); + const fail = sinon.stub().resolves(); const config = {branches: [{name: 'master'}, {name: '1.1.x'}], repositoryUrl, tagFormat: `v\${version}`}; const options = { @@ -1580,15 +1580,15 @@ test('Returns false if not running from the configured branch', async (t) => { const options = { branches: ['master'], repositoryUrl, - verifyConditions: stub().resolves(), - analyzeCommits: stub().resolves(), - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + verifyConditions: sinon.stub().resolves(), + analyzeCommits: sinon.stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1617,23 +1617,23 @@ test('Returns false if there is no relevant changes', async (t) => { await gitCommits(['First'], {cwd}); await gitPush(repositoryUrl, 'master', {cwd}); - const analyzeCommits = stub().resolves(); - const verifyRelease = stub().resolves(); - const generateNotes = stub().resolves(); - const publish = stub().resolves(); + const analyzeCommits = sinon.stub().resolves(); + const verifyRelease = sinon.stub().resolves(); + const generateNotes = sinon.stub().resolves(); + const publish = sinon.stub().resolves(); const options = { branches: ['master'], repositoryUrl, - verifyConditions: [stub().resolves()], + verifyConditions: [sinon.stub().resolves()], analyzeCommits, verifyRelease, generateNotes, - addChannel: stub().resolves(), - prepare: stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), publish, - success: stub().resolves(), - fail: stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1677,19 +1677,19 @@ test('Exclude commits with [skip release] or [release skip] from analysis', asyn {cwd} ); await gitPush(repositoryUrl, 'master', {cwd}); - const analyzeCommits = stub().resolves(); + const analyzeCommits = sinon.stub().resolves(); const config = {branches: ['master'], repositoryUrl, globalOpt: 'global'}; const options = { ...config, - verifyConditions: [stub().resolves(), stub().resolves()], + verifyConditions: [sinon.stub().resolves(), sinon.stub().resolves()], analyzeCommits, - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(), - addChannel: stub().resolves(), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(), + addChannel: sinon.stub().resolves(), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1717,8 +1717,8 @@ test('Log both plugins errors and errors thrown by "fail" plugin', async (t) => const options = { branches: ['master'], repositoryUrl, - verifyConditions: stub().rejects(pluginError), - fail: [stub().rejects(failError1), stub().rejects(failError2)], + verifyConditions: sinon.stub().rejects(pluginError), + fail: [sinon.stub().rejects(failError1), sinon.stub().rejects(failError2)], }; const semanticRelease = requireNoCache('..', { './lib/get-logger': () => t.context.logger, @@ -1737,12 +1737,12 @@ test('Log both plugins errors and errors thrown by "fail" plugin', async (t) => test('Call "fail" only if a plugin returns a SemanticReleaseError', async (t) => { const {cwd, repositoryUrl} = await gitRepo(true); const pluginError = new Error('Plugin error'); - const fail = stub().resolves(); + const fail = sinon.stub().resolves(); const options = { branches: ['master'], repositoryUrl, - verifyConditions: stub().rejects(pluginError), + verifyConditions: sinon.stub().rejects(pluginError), fail, }; const semanticRelease = requireNoCache('..', { @@ -1790,16 +1790,16 @@ test('Throw an Error if plugin returns an unexpected value', async (t) => { await gitCommits(['Second'], {cwd}); await gitPush(repositoryUrl, 'master', {cwd}); - const verifyConditions = stub().resolves(); - const analyzeCommits = stub().resolves('string'); + const verifyConditions = sinon.stub().resolves(); + const analyzeCommits = sinon.stub().resolves('string'); const options = { branches: ['master'], repositoryUrl, verifyConditions: [verifyConditions], analyzeCommits, - success: stub().resolves(), - fail: stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1816,19 +1816,19 @@ test('Throw an Error if plugin returns an unexpected value', async (t) => { test('Hide sensitive information passed to "fail" plugin', async (t) => { const {cwd, repositoryUrl} = await gitRepo(true); - const fail = stub().resolves(); + const fail = sinon.stub().resolves(); const env = {MY_TOKEN: 'secret token'}; const options = { branch: 'master', repositoryUrl, - verifyConditions: stub().throws( + verifyConditions: sinon.stub().throws( new SemanticReleaseError( `Message: Exposing token ${env.MY_TOKEN}`, 'ERR', `Details: Exposing token ${env.MY_TOKEN}` ) ), - success: stub().resolves(), + success: sinon.stub().resolves(), fail, }; @@ -1859,7 +1859,7 @@ test('Hide sensitive information passed to "success" plugin', async (t) => { await gitCommits(['feat: new feature'], {cwd}); await gitPush(repositoryUrl, 'master', {cwd}); - const success = stub().resolves(); + const success = sinon.stub().resolves(); const env = {MY_TOKEN: 'secret token'}; const options = { branch: 'master', @@ -1867,14 +1867,14 @@ test('Hide sensitive information passed to "success" plugin', async (t) => { verifyConditions: false, verifyRelease: false, prepare: false, - generateNotes: stub().resolves(`Exposing token ${env.MY_TOKEN}`), - publish: stub().resolves({ + generateNotes: sinon.stub().resolves(`Exposing token ${env.MY_TOKEN}`), + publish: sinon.stub().resolves({ name: `Name: Exposing token ${env.MY_TOKEN}`, url: `URL: Exposing token ${env.MY_TOKEN}`, }), addChannel: false, success, - fail: stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { @@ -1912,19 +1912,19 @@ test('Get all commits including the ones not in the shallow clone', async (t) => channel: undefined, }; const notes = 'Release notes'; - const analyzeCommits = stub().resolves(nextRelease.type); + const analyzeCommits = sinon.stub().resolves(nextRelease.type); const config = {branches: ['master'], repositoryUrl, globalOpt: 'global'}; const options = { ...config, - verifyConditions: stub().resolves(), + verifyConditions: sinon.stub().resolves(), analyzeCommits, - verifyRelease: stub().resolves(), - generateNotes: stub().resolves(notes), - prepare: stub().resolves(), - publish: stub().resolves(), - success: stub().resolves(), - fail: stub().resolves(), + verifyRelease: sinon.stub().resolves(), + generateNotes: sinon.stub().resolves(notes), + prepare: sinon.stub().resolves(), + publish: sinon.stub().resolves(), + success: sinon.stub().resolves(), + fail: sinon.stub().resolves(), }; const semanticRelease = requireNoCache('..', { diff --git a/test/plugins/normalize.test.js b/test/plugins/normalize.test.js index 57613943..12a297e2 100644 --- a/test/plugins/normalize.test.js +++ b/test/plugins/normalize.test.js @@ -1,16 +1,16 @@ import test from 'ava'; import {noop} from 'lodash'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import normalize from '../../lib/plugins/normalize.js'; const cwd = process.cwd(); test.beforeEach((t) => { // Stub the logger functions - t.context.log = stub(); - t.context.error = stub(); - t.context.success = stub(); - t.context.stderr = {write: stub()}; + t.context.log = sinon.stub); + t.context.error = sinon.stub); + t.context.success = sinon.stub); + t.context.stderr = {write: sinon.stub)}; t.context.logger = { log: t.context.log, error: t.context.error, @@ -99,7 +99,7 @@ test('Normalize and load plugin that retuns multiple functions', (t) => { }); test('Wrap "analyzeCommits" plugin in a function that validate the output of the plugin', async (t) => { - const analyzeCommits = stub().resolves(2); + const analyzeCommits = sinon.stub).resolves(2); const plugin = normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'analyzeCommits', @@ -117,7 +117,7 @@ test('Wrap "analyzeCommits" plugin in a function that validate the output of the }); test('Wrap "generateNotes" plugin in a function that validate the output of the plugin', async (t) => { - const generateNotes = stub().resolves(2); + const generateNotes = sinon.stub).resolves(2); const plugin = normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'generateNotes', @@ -135,7 +135,7 @@ test('Wrap "generateNotes" plugin in a function that validate the output of the }); test('Wrap "publish" plugin in a function that validate the output of the plugin', async (t) => { - const publish = stub().resolves(2); + const publish = sinon.stub).resolves(2); const plugin = normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'publish', @@ -153,7 +153,7 @@ test('Wrap "publish" plugin in a function that validate the output of the plugin }); test('Wrap "addChannel" plugin in a function that validate the output of the plugin', async (t) => { - const addChannel = stub().resolves(2); + const addChannel = sinon.stub).resolves(2); const plugin = normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'addChannel', @@ -171,7 +171,7 @@ test('Wrap "addChannel" plugin in a function that validate the output of the plu }); test('Plugin is called with "pluginConfig" (with object definition) and input', async (t) => { - const pluginFunction = stub().resolves(); + const pluginFunction = sinon.stub).resolves(); const pluginConf = {path: pluginFunction, conf: 'confValue'}; const options = {global: 'globalValue'}; const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); @@ -186,7 +186,7 @@ test('Plugin is called with "pluginConfig" (with object definition) and input', }); test('Plugin is called with "pluginConfig" (with array definition) and input', async (t) => { - const pluginFunction = stub().resolves(); + const pluginFunction = sinon.stub).resolves(); const pluginConf = [pluginFunction, {conf: 'confValue'}]; const options = {global: 'globalValue'}; const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); @@ -201,7 +201,7 @@ test('Plugin is called with "pluginConfig" (with array definition) and input', a }); test('Prevent plugins to modify "pluginConfig"', async (t) => { - const pluginFunction = stub().callsFake((pluginConfig) => { + const pluginFunction = sinon.stub).callsFake((pluginConfig) => { pluginConfig.conf.subConf = 'otherConf'; }); const pluginConf = {path: pluginFunction, conf: {subConf: 'originalConf'}}; @@ -214,7 +214,7 @@ test('Prevent plugins to modify "pluginConfig"', async (t) => { }); test('Prevent plugins to modify its input', async (t) => { - const pluginFunction = stub().callsFake((pluginConfig, options) => { + const pluginFunction = sinon.stub).callsFake((pluginConfig, options) => { options.param.subParam = 'otherParam'; }); const input = {param: {subParam: 'originalSubParam'}, options: {}}; diff --git a/test/plugins/pipeline.test.js b/test/plugins/pipeline.test.js index cda4f27a..c986840e 100644 --- a/test/plugins/pipeline.test.js +++ b/test/plugins/pipeline.test.js @@ -1,12 +1,12 @@ import test from 'ava'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import AggregateError from 'aggregate-error'; import pipeline from '../../lib/plugins/pipeline.js'; test('Execute each function in series passing the same input', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().resolves(2); - const step3 = stub().resolves(3); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).resolves(2); + const step3 = sinon.stub).resolves(3); const result = await pipeline([step1, step2, step3])(0); t.deepEqual(result, [1, 2, 3]); @@ -19,10 +19,10 @@ test('Execute each function in series passing the same input', async (t) => { }); test('Execute each function in series passing a transformed input from "getNextInput"', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().resolves(2); - const step3 = stub().resolves(3); - const step4 = stub().resolves(4); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).resolves(2); + const step3 = sinon.stub).resolves(3); + const step4 = sinon.stub).resolves(4); const getNextInput = (lastResult, result) => lastResult + result; const result = await pipeline([step1, step2, step3, step4], {settleAll: false, getNextInput})(0); @@ -38,11 +38,11 @@ test('Execute each function in series passing a transformed input from "getNextI }); test('Execute each function in series passing the "lastResult" and "result" to "getNextInput"', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().resolves(2); - const step3 = stub().resolves(3); - const step4 = stub().resolves(4); - const getNextInput = stub().returnsArg(0); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).resolves(2); + const step3 = sinon.stub).resolves(3); + const step4 = sinon.stub).resolves(4); + const getNextInput = sinon.stub).returnsArg(0); const result = await pipeline([step1, step2, step3, step4], {settleAll: false, getNextInput})(5); @@ -56,12 +56,12 @@ test('Execute each function in series passing the "lastResult" and "result" to " }); test('Execute each function in series calling "transform" to modify the results', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().resolves(2); - const step3 = stub().resolves(3); - const step4 = stub().resolves(4); - const getNextInput = stub().returnsArg(0); - const transform = stub().callsFake((result) => result + 1); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).resolves(2); + const step3 = sinon.stub).resolves(3); + const step4 = sinon.stub).resolves(4); + const getNextInput = sinon.stub).returnsArg(0); + const transform = sinon.stub).callsFake((result) => result + 1); const result = await pipeline([step1, step2, step3, step4], {getNextInput, transform})(5); @@ -75,12 +75,12 @@ test('Execute each function in series calling "transform" to modify the results' }); test('Execute each function in series calling "transform" to modify the results with "settleAll"', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().resolves(2); - const step3 = stub().resolves(3); - const step4 = stub().resolves(4); - const getNextInput = stub().returnsArg(0); - const transform = stub().callsFake((result) => result + 1); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).resolves(2); + const step3 = sinon.stub).resolves(3); + const step4 = sinon.stub).resolves(4); + const getNextInput = sinon.stub).returnsArg(0); + const transform = sinon.stub).callsFake((result) => result + 1); const result = await pipeline([step1, step2, step3, step4], {settleAll: true, getNextInput, transform})(5); @@ -94,9 +94,9 @@ test('Execute each function in series calling "transform" to modify the results }); test('Stop execution and throw error if a step rejects', async (t) => { - const step1 = stub().resolves(1); - const step2 = stub().rejects(new Error('test error')); - const step3 = stub().resolves(3); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).rejects(new Error('test error')); + const step3 = sinon.stub).resolves(3); const error = await t.throwsAsync(pipeline([step1, step2, step3])(0), { instanceOf: Error, @@ -112,9 +112,9 @@ test('Throw all errors from the first step throwing an AggregateError', async (t const error1 = new Error('test error 1'); const error2 = new Error('test error 2'); - const step1 = stub().resolves(1); - const step2 = stub().rejects(new AggregateError([error1, error2])); - const step3 = stub().resolves(3); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).rejects(new AggregateError([error1, error2])); + const step3 = sinon.stub).resolves(3); const errors = await t.throwsAsync(pipeline([step1, step2, step3])(0)); @@ -127,9 +127,9 @@ test('Throw all errors from the first step throwing an AggregateError', async (t test('Execute all even if a Promise rejects', async (t) => { const error1 = new Error('test error 1'); const error2 = new Error('test error 2'); - const step1 = stub().resolves(1); - const step2 = stub().rejects(error1); - const step3 = stub().rejects(error2); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).rejects(error1); + const step3 = sinon.stub).rejects(error2); const errors = await t.throwsAsync(pipeline([step1, step2, step3], {settleAll: true})(0)); @@ -144,8 +144,8 @@ test('Throw all errors from all steps throwing an AggregateError', async (t) => const error2 = new Error('test error 2'); const error3 = new Error('test error 3'); const error4 = new Error('test error 4'); - const step1 = stub().rejects(new AggregateError([error1, error2])); - const step2 = stub().rejects(new AggregateError([error3, error4])); + const step1 = sinon.stub).rejects(new AggregateError([error1, error2])); + const step2 = sinon.stub).rejects(new AggregateError([error3, error4])); const errors = await t.throwsAsync(pipeline([step1, step2], {settleAll: true})(0)); @@ -157,10 +157,10 @@ test('Throw all errors from all steps throwing an AggregateError', async (t) => test('Execute each function in series passing a transformed input even if a step rejects', async (t) => { const error2 = new Error('test error 2'); const error3 = new Error('test error 3'); - const step1 = stub().resolves(1); - const step2 = stub().rejects(error2); - const step3 = stub().rejects(error3); - const step4 = stub().resolves(4); + const step1 = sinon.stub).resolves(1); + const step2 = sinon.stub).rejects(error2); + const step3 = sinon.stub).rejects(error3); + const step4 = sinon.stub).resolves(4); const getNextInput = (previousResult, result) => previousResult + result; const errors = await t.throwsAsync(pipeline([step1, step2, step3, step4], {settleAll: true, getNextInput})(0)); diff --git a/test/plugins/plugins.test.js b/test/plugins/plugins.test.js index 551e65e2..a9ca7956 100644 --- a/test/plugins/plugins.test.js +++ b/test/plugins/plugins.test.js @@ -1,7 +1,7 @@ import path from 'path'; import test from 'ava'; import {copy, outputFile} from 'fs-extra'; -import {stub} from 'sinon'; +import sinon from 'sinon'; import tempy from 'tempy'; import getPlugins from '../../lib/plugins'; @@ -10,8 +10,8 @@ const cwd = process.cwd(); test.beforeEach((t) => { // Stub the logger functions - t.context.log = stub(); - t.context.success = stub(); + t.context.log = sinon.stub); + t.context.success = sinon.stub); t.context.logger = {log: t.context.log, success: t.context.success, scope: () => t.context.logger}; }); @@ -56,8 +56,8 @@ test('Export plugins based on steps config', (t) => { }); test('Export plugins based on "plugins" config (array)', async (t) => { - const plugin1 = {verifyConditions: stub(), publish: stub()}; - const plugin2 = {verifyConditions: stub(), verifyRelease: stub()}; + const plugin1 = {verifyConditions: sinon.stub), publish: sinon.stub)}; + const plugin2 = {verifyConditions: sinon.stub), verifyRelease: sinon.stub)}; const plugins = getPlugins( {cwd, logger: t.context.logger, options: {plugins: [plugin1, [plugin2, {}]], verifyRelease: () => {}}}, {} @@ -85,7 +85,7 @@ test('Export plugins based on "plugins" config (array)', async (t) => { }); test('Export plugins based on "plugins" config (single definition)', async (t) => { - const plugin1 = {verifyConditions: stub(), publish: stub()}; + const plugin1 = {verifyConditions: sinon.stub), publish: sinon.stub)}; const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: plugin1}}, {}); await plugins.verifyConditions({options: {}}); @@ -106,8 +106,8 @@ test('Export plugins based on "plugins" config (single definition)', async (t) = }); test('Merge global options, "plugins" options and step options', async (t) => { - const plugin1 = [{verifyConditions: stub(), publish: stub()}, {pluginOpt1: 'plugin1'}]; - const plugin2 = [{verifyConditions: stub()}, {pluginOpt2: 'plugin2'}]; + const plugin1 = [{verifyConditions: sinon.stub), publish: sinon.stub)}, {pluginOpt1: 'plugin1'}]; + const plugin2 = [{verifyConditions: sinon.stub)}, {pluginOpt2: 'plugin2'}]; const plugin3 = [stub(), {pluginOpt3: 'plugin3'}]; const plugins = getPlugins( {