From 242deb5564ffcf98a6f73801d9f7780d96fde24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iiro=20J=C3=A4ppinen?= Date: Sun, 7 Jul 2019 00:48:04 +0300 Subject: [PATCH] feat: add --relative option for controlling file paths All commands specified in the configuration will run in the current directory when using relative paths, instead of git commands running in the repo root --- bin/lint-staged | 6 +- src/generateTasks.js | 25 +++-- src/index.js | 13 +-- src/makeCmdTasks.js | 8 +- src/resolveGitDir.js | 2 +- src/resolveTaskFn.js | 34 ++++--- src/runAll.js | 46 ++++----- ...c.js.snap => runAll.unmocked.spec.js.snap} | 0 test/generateTasks.spec.js | 93 ++++++++++++------- test/makeCmdTasks.spec.js | 36 ++++--- test/resolveTaskFn.spec.js | 18 ++++ test/runAll.2.spec.js | 10 -- test/runAll.spec.js | 20 ++-- test/runAll.unmocked.spec.js | 12 +++ 14 files changed, 199 insertions(+), 124 deletions(-) rename test/__snapshots__/{runAll.2.spec.js.snap => runAll.unmocked.spec.js.snap} (100%) delete mode 100644 test/runAll.2.spec.js create mode 100644 test/runAll.unmocked.spec.js diff --git a/bin/lint-staged b/bin/lint-staged index 412799312..7a1d9331c 100755 --- a/bin/lint-staged +++ b/bin/lint-staged @@ -27,8 +27,9 @@ const debug = debugLib('lint-staged:bin') cmdline .version(pkg.version) .option('-c, --config [path]', 'Path to configuration file') - .option('-x, --shell', 'Use execa’s shell mode to execute linter commands') - .option('-q, --quiet', 'Use Listr’s silent renderer') + .option('-r, --relative', 'Pass relative filepaths to tasks') + .option('-x, --shell', 'Skip parsing of tasks for better shell support') + .option('-q, --quiet', 'Disable lint-staged’s own console output') .option('-d, --debug', 'Enable debug mode') .parse(process.argv) @@ -40,6 +41,7 @@ debug('Running `lint-staged@%s`', pkg.version) lintStaged({ configPath: cmdline.config, + relative: !!cmdline.relative, shell: !!cmdline.shell, quiet: !!cmdline.quiet, debug: !!cmdline.debug diff --git a/src/generateTasks.js b/src/generateTasks.js index d74201260..0f632edc3 100644 --- a/src/generateTasks.js +++ b/src/generateTasks.js @@ -18,15 +18,25 @@ const isPathInside = (parent, child) => { return relative && !relative.startsWith('..') && !path.isAbsolute(relative) } -module.exports = async function generateTasks(linters, gitDir, stagedRelFiles) { +/** + * Generates all task commands, and filelist + * + * @param {object} options + * @param {Object} [options.config] - Task configuration + * @param {boolean} [options.gitDir] - Git root directory + * @param {boolean} [options.files] - Staged filepaths + * @param {boolean} [options.relative] - Whether filepaths to should be relative to gitDir + * @returns {Promise} + */ +module.exports = async function generateTasks({ config, gitDir, files, relative = false }) { debug('Generating linter tasks') const cwd = process.cwd() - const stagedFiles = stagedRelFiles.map(file => path.resolve(gitDir, file)) + const stagedFiles = files.map(file => path.resolve(gitDir, file)) - return Object.keys(linters).map(pattern => { + return Object.keys(config).map(pattern => { const isParentDirPattern = pattern.startsWith('../') - const commands = linters[pattern] + const commands = config[pattern] const fileList = micromatch( stagedFiles @@ -43,9 +53,10 @@ module.exports = async function generateTasks(linters, gitDir, stagedRelFiles) { matchBase: !pattern.includes('/'), dot: true } - ).map(file => - // Return absolute path after the filter is run - path.resolve(cwd, file) + ).map( + file => + // Return absolute path after the filter is run + relative ? path.normalize(file) : path.resolve(cwd, file) ) const task = { pattern, commands, fileList } diff --git a/src/index.js b/src/index.js index f8afd8a6b..759e1c535 100644 --- a/src/index.js +++ b/src/index.js @@ -43,15 +43,16 @@ function loadConfig(configPath) { * * @param {object} options * @param {string} [options.configPath] - Path to configuration file - * @param {boolean} [options.shell] - Use execa’s shell mode to execute linter commands - * @param {boolean} [options.quiet] - Use Listr’s silent renderer + * @param {boolean} [options.relative] - Pass relative filepaths to tasks + * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support + * @param {boolean} [options.quiet] - Disable lint-staged’s own console output * @param {boolean} [options.debug] - Enable debug mode * @param {Logger} [logger] * * @returns {Promise} Promise of whether the linting passed or failed */ module.exports = function lintStaged( - { configPath, shell = false, quiet = false, debug = false } = {}, + { configPath, relative = false, shell = false, quiet = false, debug = false } = {}, logger = console ) { debugLog('Loading config using `cosmiconfig`') @@ -71,12 +72,12 @@ module.exports = function lintStaged( } else { // We might not be in debug mode but `DEBUG=lint-staged*` could have // been set. - debugLog('Normalized config:\n%O', config) + debugLog('lint-staged config:\n%O', config) } - return runAll(config, shell, quiet, debug, logger) + return runAll({ config, relative, shell, quiet, debug }, logger) .then(() => { - debugLog('linters were executed successfully!') + debugLog('tasks were executed successfully!') return Promise.resolve(true) }) .catch(error => { diff --git a/src/makeCmdTasks.js b/src/makeCmdTasks.js index d07ec66a4..90726c2fa 100644 --- a/src/makeCmdTasks.js +++ b/src/makeCmdTasks.js @@ -7,11 +7,13 @@ const debug = require('debug')('lint-staged:make-cmd-tasks') /** * Creates and returns an array of listr tasks which map to the given commands. * - * @param {Array|string|Function} commands + * @param {object} options + * @param {Array|string|Function} [options.commands] + * @param {string} [options.gitDir] + * @param {Array} [options.pathsToLint] * @param {Boolean} shell - * @param {Array} pathsToLint */ -module.exports = async function makeCmdTasks(commands, shell, gitDir, pathsToLint) { +module.exports = async function makeCmdTasks({ commands, gitDir, pathsToLint, shell }) { debug('Creating listr tasks for commands %o', commands) const commandsArray = Array.isArray(commands) ? commands : [commands] diff --git a/src/resolveGitDir.js b/src/resolveGitDir.js index 786daf6d9..0fc656974 100644 --- a/src/resolveGitDir.js +++ b/src/resolveGitDir.js @@ -3,7 +3,7 @@ const execGit = require('./execGit') const path = require('path') -module.exports = async function resolveGitDir(options) { +module.exports = async function resolveGitDir(options = {}) { try { // git cli uses GIT_DIR to fast track its response however it might be set to a different path // depending on where the caller initiated this from, hence clear GIT_DIR diff --git a/src/resolveTaskFn.js b/src/resolveTaskFn.js index 6b0410243..a4cebdb44 100644 --- a/src/resolveTaskFn.js +++ b/src/resolveTaskFn.js @@ -77,16 +77,32 @@ function makeErr(linter, result, context = {}) { * if the OS is Windows. * * @param {Object} options - * @param {string} options.gitDir - * @param {Boolean} options.isFn - * @param {string} options.linter - * @param {Array} options.pathsToLint - * @param {Boolean} [options.shell] + * @param {String} [options.gitDir] - Current git repo path + * @param {Boolean} [options.isFn] - Whether the linter task is a function + * @param {string} [options.linter] — Linter task + * @param {Array} [options.pathsToLint] — Filepaths to run the linter task against + * @param {Boolean} [options.relative] — Whether the filepaths should be relative + * @param {Boolean} [options.shell] — Whether to skip parsing linter task for better shell support * @returns {function(): Promise>} */ -module.exports = function resolveTaskFn({ gitDir, isFn, linter, pathsToLint, shell = false }) { +module.exports = function resolveTaskFn({ + gitDir, + isFn, + linter, + pathsToLint, + relative, + shell = false +}) { const execaOptions = { preferLocal: true, reject: false, shell } + if (relative) { + execaOptions.cwd = process.cwd() + } else if (/^git(\.exe)?/i.test(linter) && gitDir !== process.cwd()) { + // Only use gitDir as CWD if we are using the git binary + // e.g `npm` should run tasks in the actual CWD + execaOptions.cwd = gitDir + } + let cmd let args @@ -101,12 +117,6 @@ module.exports = function resolveTaskFn({ gitDir, isFn, linter, pathsToLint, she args = isFn ? parsedArgs : parsedArgs.concat(pathsToLint) } - // Only use gitDir as CWD if we are using the git binary - // e.g `npm` should run tasks in the actual CWD - if (/^git(\.exe)?/i.test(linter) && gitDir !== process.cwd()) { - execaOptions.cwd = gitDir - } - return ctx => execLinter(cmd, args, execaOptions).then(result => { if (result.failed || result.killed || result.signal != null) { diff --git a/src/runAll.js b/src/runAll.js index 62f23b65b..27d19212e 100644 --- a/src/runAll.js +++ b/src/runAll.js @@ -13,7 +13,7 @@ const git = require('./gitWorkflow') const makeCmdTasks = require('./makeCmdTasks') const resolveGitDir = require('./resolveGitDir') -const debug = require('debug')('lint-staged:run') +const debugLog = require('debug')('lint-staged:run') /** * https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x @@ -26,29 +26,28 @@ const MAX_ARG_LENGTH = /** * Executes all tasks and either resolves or rejects the promise * - * @param config {Object} - * @param {Boolean} [shellMode] Use execa’s shell mode to execute linter commands - * @param {Boolean} [quietMode] Use Listr’s silent renderer - * @param {Boolean} [debugMode] Enable debug mode + * @param {object} options + * @param {Object} [options.config] - Task configuration + * @param {boolean} [options.relative] - Pass relative filepaths to tasks + * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support + * @param {boolean} [options.quiet] - Disable lint-staged’s own console output + * @param {boolean} [options.debug] - Enable debug mode * @param {Logger} logger * @returns {Promise} */ module.exports = async function runAll( - config, - shellMode = false, - quietMode = false, - debugMode = false, + { config, relative = false, shell = false, quiet = false, debug = false }, logger = console ) { - debug('Running all linter scripts') + debugLog('Running all linter scripts') - const gitDir = await resolveGitDir(config) + const gitDir = await resolveGitDir() if (!gitDir) { throw new Error('Current directory is not a git directory!') } - debug('Resolved git directory to be `%s`', gitDir) + debugLog('Resolved git directory to be `%s`', gitDir) const files = await getStagedFiles({ cwd: gitDir }) @@ -56,7 +55,7 @@ module.exports = async function runAll( throw new Error('Unable to get staged files!') } - debug('Loaded list of staged files in git:\n%O', files) + debugLog('Loaded list of staged files in git:\n%O', files) const argLength = files.join(' ').length if (argLength > MAX_ARG_LENGTH) { @@ -70,16 +69,19 @@ https://github.com/okonet/lint-staged#using-js-functions-to-customize-linter-com ) } - const tasks = (await generateTasks(config, gitDir, files)).map(task => ({ + const tasks = (await generateTasks({ config, gitDir, files, relative })).map(task => ({ title: `Running tasks for ${task.pattern}`, task: async () => - new Listr(await makeCmdTasks(task.commands, shellMode, gitDir, task.fileList), { - // In sub-tasks we don't want to run concurrently - // and we want to abort on errors - dateFormat: false, - concurrent: false, - exitOnError: true - }), + new Listr( + await makeCmdTasks({ commands: task.commands, gitDir, shell, pathsToLint: task.fileList }), + { + // In sub-tasks we don't want to run concurrently + // and we want to abort on errors + dateFormat: false, + concurrent: false, + exitOnError: true + } + ), skip: () => { if (task.fileList.length === 0) { return `No staged files match ${task.pattern}` @@ -90,7 +92,7 @@ https://github.com/okonet/lint-staged#using-js-functions-to-customize-linter-com const listrOptions = { dateFormat: false, - renderer: (quietMode && 'silent') || (debugMode && 'verbose') || 'update' + renderer: (quiet && 'silent') || (debug && 'verbose') || 'update' } // If all of the configured "linters" should be skipped diff --git a/test/__snapshots__/runAll.2.spec.js.snap b/test/__snapshots__/runAll.unmocked.spec.js.snap similarity index 100% rename from test/__snapshots__/runAll.2.spec.js.snap rename to test/__snapshots__/runAll.unmocked.spec.js.snap diff --git a/test/generateTasks.spec.js b/test/generateTasks.spec.js index ec9ae21ba..e5edfe5b2 100644 --- a/test/generateTasks.spec.js +++ b/test/generateTasks.spec.js @@ -25,8 +25,8 @@ const files = [ // Mocks get hoisted jest.mock('../src/resolveGitDir.js') -const workDir = path.join(os.tmpdir(), 'tmp-lint-staged') -resolveGitDir.mockResolvedValue(workDir) +const gitDir = path.join(os.tmpdir(), 'tmp-lint-staged') +resolveGitDir.mockResolvedValue(gitDir) const config = { '*.js': 'root-js', @@ -39,7 +39,7 @@ const config = { describe('generateTasks', () => { beforeAll(() => { - jest.spyOn(process, 'cwd').mockReturnValue(workDir) + jest.spyOn(process, 'cwd').mockReturnValue(gitDir) }) afterAll(() => { @@ -47,13 +47,13 @@ describe('generateTasks', () => { }) it('should return absolute paths', async () => { - const [task] = await generateTasks( - { + const [task] = await generateTasks({ + config: { '*': 'lint' }, - workDir, + gitDir, files - ) + }) task.fileList.forEach(file => { expect(path.isAbsolute(file)).toBe(true) }) @@ -61,7 +61,7 @@ describe('generateTasks', () => { it('should not match non-children files', async () => { const relPath = path.join(process.cwd(), '..') - const result = await generateTasks({ ...config }, relPath, files) + const result = await generateTasks({ config, gitDir: relPath, files }) const linter = result.find(item => item.pattern === '*.js') expect(linter).toEqual({ pattern: '*.js', @@ -71,7 +71,7 @@ describe('generateTasks', () => { }) it('should return an empty file list for linters with no matches.', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) result.forEach(task => { if (task.commands === 'unknown-js') { @@ -83,74 +83,95 @@ describe('generateTasks', () => { }) it('should match pattern "*.js"', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) const linter = result.find(item => item.pattern === '*.js') expect(linter).toEqual({ pattern: '*.js', commands: 'root-js', fileList: [ - `${workDir}/test.js`, - `${workDir}/deeper/test.js`, - `${workDir}/deeper/test2.js`, - `${workDir}/even/deeper/test.js`, - `${workDir}/.hidden/test.js` + `${gitDir}/test.js`, + `${gitDir}/deeper/test.js`, + `${gitDir}/deeper/test2.js`, + `${gitDir}/even/deeper/test.js`, + `${gitDir}/.hidden/test.js` ].map(path.normalize) }) }) it('should match pattern "**/*.js"', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) const linter = result.find(item => item.pattern === '**/*.js') expect(linter).toEqual({ pattern: '**/*.js', commands: 'any-js', fileList: [ - `${workDir}/test.js`, - `${workDir}/deeper/test.js`, - `${workDir}/deeper/test2.js`, - `${workDir}/even/deeper/test.js`, - `${workDir}/.hidden/test.js` + `${gitDir}/test.js`, + `${gitDir}/deeper/test.js`, + `${gitDir}/deeper/test2.js`, + `${gitDir}/even/deeper/test.js`, + `${gitDir}/.hidden/test.js` ].map(path.normalize) }) }) it('should match pattern "deeper/*.js"', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) const linter = result.find(item => item.pattern === 'deeper/*.js') expect(linter).toEqual({ pattern: 'deeper/*.js', commands: 'deeper-js', - fileList: [`${workDir}/deeper/test.js`, `${workDir}/deeper/test2.js`].map(path.normalize) + fileList: [`${gitDir}/deeper/test.js`, `${gitDir}/deeper/test2.js`].map(path.normalize) }) }) it('should match pattern ".hidden/*.js"', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) const linter = result.find(item => item.pattern === '.hidden/*.js') expect(linter).toEqual({ pattern: '.hidden/*.js', commands: 'hidden-js', - fileList: [path.normalize(`${workDir}/.hidden/test.js`)] + fileList: [path.normalize(`${gitDir}/.hidden/test.js`)] }) }) it('should match pattern "*.{css,js}"', async () => { - const result = await generateTasks(config, workDir, files) + const result = await generateTasks({ config, gitDir, files }) + const linter = result.find(item => item.pattern === '*.{css,js}') + expect(linter).toEqual({ + pattern: '*.{css,js}', + commands: 'root-css-or-js', + fileList: [ + `${gitDir}/test.js`, + `${gitDir}/deeper/test.js`, + `${gitDir}/deeper/test2.js`, + `${gitDir}/even/deeper/test.js`, + `${gitDir}/.hidden/test.js`, + `${gitDir}/test.css`, + `${gitDir}/deeper/test.css`, + `${gitDir}/deeper/test2.css`, + `${gitDir}/even/deeper/test.css`, + `${gitDir}/.hidden/test.css` + ].map(path.normalize) + }) + }) + + it('should be able to return relative paths for "*.{css,js}"', async () => { + const result = await generateTasks({ config, gitDir, files, relative: true }) const linter = result.find(item => item.pattern === '*.{css,js}') expect(linter).toEqual({ pattern: '*.{css,js}', commands: 'root-css-or-js', fileList: [ - `${workDir}/test.js`, - `${workDir}/deeper/test.js`, - `${workDir}/deeper/test2.js`, - `${workDir}/even/deeper/test.js`, - `${workDir}/.hidden/test.js`, - `${workDir}/test.css`, - `${workDir}/deeper/test.css`, - `${workDir}/deeper/test2.css`, - `${workDir}/even/deeper/test.css`, - `${workDir}/.hidden/test.css` + 'test.js', + 'deeper/test.js', + 'deeper/test2.js', + 'even/deeper/test.js', + '.hidden/test.js', + 'test.css', + 'deeper/test.css', + 'deeper/test2.css', + 'even/deeper/test.css', + '.hidden/test.css' ].map(path.normalize) }) }) diff --git a/test/makeCmdTasks.spec.js b/test/makeCmdTasks.spec.js index 037df25e0..e9919e4b2 100644 --- a/test/makeCmdTasks.spec.js +++ b/test/makeCmdTasks.spec.js @@ -9,13 +9,13 @@ describe('makeCmdTasks', () => { }) it('should return an array', async () => { - const array = await makeCmdTasks('test', false, gitDir, ['test.js']) + const array = await makeCmdTasks({ commands: 'test', gitDir, pathsToLint: ['test.js'] }) expect(array).toBeInstanceOf(Array) }) it('should work with a single command', async () => { expect.assertions(4) - const res = await makeCmdTasks('test', false, gitDir, ['test.js']) + const res = await makeCmdTasks({ commands: 'test', gitDir, pathsToLint: ['test.js'] }) expect(res.length).toBe(1) const [linter] = res expect(linter.title).toBe('test') @@ -27,7 +27,11 @@ describe('makeCmdTasks', () => { it('should work with multiple commands', async () => { expect.assertions(9) - const res = await makeCmdTasks(['test', 'test2'], false, gitDir, ['test.js']) + const res = await makeCmdTasks({ + commands: ['test', 'test2'], + gitDir, + pathsToLint: ['test.js'] + }) expect(res.length).toBe(2) const [linter1, linter2] = res expect(linter1.title).toBe('test') @@ -54,37 +58,39 @@ describe('makeCmdTasks', () => { }) it('should work with function linter returning a string', async () => { - const res = await makeCmdTasks(() => 'test', false, gitDir, ['test.js']) + const res = await makeCmdTasks({ commands: () => 'test', gitDir, pathsToLint: ['test.js'] }) expect(res.length).toBe(1) expect(res[0].title).toEqual('test') }) it('should work with function linter returning array of string', async () => { - const res = await makeCmdTasks(() => ['test', 'test2'], false, gitDir, ['test.js']) + const res = await makeCmdTasks({ + commands: () => ['test', 'test2'], + gitDir, + pathsToLint: ['test.js'] + }) expect(res.length).toBe(2) expect(res[0].title).toEqual('test') expect(res[1].title).toEqual('test2') }) it('should work with function linter accepting arguments', async () => { - const res = await makeCmdTasks( - filenames => filenames.map(file => `test ${file}`), - false, + const res = await makeCmdTasks({ + commands: filenames => filenames.map(file => `test ${file}`), gitDir, - ['test.js', 'test2.js'] - ) + pathsToLint: ['test.js', 'test2.js'] + }) expect(res.length).toBe(2) expect(res[0].title).toEqual('test test.js') expect(res[1].title).toEqual('test test2.js') }) it('should work with array of mixed string and function linters', async () => { - const res = await makeCmdTasks( - [() => 'test', 'test2', files => files.map(file => `test ${file}`)], - false, + const res = await makeCmdTasks({ + commands: [() => 'test', 'test2', files => files.map(file => `test ${file}`)], gitDir, - ['test.js', 'test2.js', 'test3.js'] - ) + pathsToLint: ['test.js', 'test2.js', 'test3.js'] + }) expect(res.length).toBe(5) expect(res[0].title).toEqual('test') expect(res[1].title).toEqual('test2') diff --git a/test/resolveTaskFn.spec.js b/test/resolveTaskFn.spec.js index 783d83a7e..42dd41748 100644 --- a/test/resolveTaskFn.spec.js +++ b/test/resolveTaskFn.spec.js @@ -107,6 +107,24 @@ describe('resolveTaskFn', () => { }) }) + it('should always pass `process.cwd()` as `cwd` to `execa()` when relative = true', async () => { + expect.assertions(2) + const taskFn = resolveTaskFn({ + ...defaultOpts, + linter: 'git add', + relative: true + }) + + await taskFn() + expect(execa).toHaveBeenCalledTimes(1) + expect(execa).lastCalledWith('git', ['add', 'test.js'], { + cwd: process.cwd(), + preferLocal: true, + reject: false, + shell: false + }) + }) + it('should throw error for failed linters', async () => { expect.assertions(1) execa.mockResolvedValueOnce({ diff --git a/test/runAll.2.spec.js b/test/runAll.2.spec.js deleted file mode 100644 index 136673366..000000000 --- a/test/runAll.2.spec.js +++ /dev/null @@ -1,10 +0,0 @@ -import runAll from '../src/runAll' - -jest.unmock('execa') - -describe('runAll', () => { - it('should throw when not in a git directory', async () => { - const config = { cwd: '/' } - await expect(runAll(config)).rejects.toThrowErrorMatchingSnapshot() - }) -}) diff --git a/test/runAll.spec.js b/test/runAll.spec.js index d52eaf7f2..641c83c44 100644 --- a/test/runAll.spec.js +++ b/test/runAll.spec.js @@ -38,28 +38,28 @@ describe('runAll', () => { it('should resolve the promise with no tasks', async () => { expect.assertions(1) - const res = await runAll({}) + const res = await runAll({ config: {} }) expect(res).toEqual('No tasks to run.') }) it('should resolve the promise with no files', async () => { expect.assertions(1) - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) expect(console.printHistory()).toMatchSnapshot() }) it('should use an injected logger', async () => { expect.assertions(1) const logger = makeConsoleMock() - await runAll({ '*.js': ['echo "sample"'] }, undefined, true, undefined, logger) + await runAll({ config: { '*.js': ['echo "sample"'] }, debug: true }, logger) expect(logger.printHistory()).toMatchSnapshot() }) it('should not skip tasks if there are files', async () => { expect.assertions(1) getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) expect(console.printHistory()).toMatchSnapshot() }) @@ -67,7 +67,7 @@ describe('runAll', () => { expect.assertions(4) hasPartiallyStagedFiles.mockImplementationOnce(() => Promise.resolve(true)) getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) expect(gitStashSave).toHaveBeenCalledTimes(1) expect(updateStash).toHaveBeenCalledTimes(1) expect(gitStashPop).toHaveBeenCalledTimes(1) @@ -78,7 +78,7 @@ describe('runAll', () => { expect.assertions(4) hasPartiallyStagedFiles.mockImplementationOnce(() => Promise.resolve(false)) getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) expect(gitStashSave).toHaveBeenCalledTimes(0) expect(updateStash).toHaveBeenCalledTimes(0) expect(gitStashPop).toHaveBeenCalledTimes(0) @@ -100,7 +100,7 @@ describe('runAll', () => { ) try { - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) } catch (err) { console.log(err) } @@ -115,7 +115,7 @@ describe('runAll', () => { getStagedFiles.mockImplementationOnce(async () => new Array(100000).fill('sample.js')) try { - await runAll({ '*.js': () => 'echo "sample"' }) + await runAll({ config: { '*.js': () => 'echo "sample"' } }) } catch (err) { console.log(err) } @@ -139,7 +139,7 @@ describe('runAll', () => { ) try { - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) } catch (err) { console.log(err) } @@ -170,7 +170,7 @@ describe('runAll', () => { ) try { - await runAll({ '*.js': ['echo "sample"'] }) + await runAll({ config: { '*.js': ['echo "sample"'] } }) } catch (err) { console.log(err) } diff --git a/test/runAll.unmocked.spec.js b/test/runAll.unmocked.spec.js new file mode 100644 index 000000000..fffa0688d --- /dev/null +++ b/test/runAll.unmocked.spec.js @@ -0,0 +1,12 @@ +import runAll from '../src/runAll' +import resolveGitDir from '../src/resolveGitDir' + +jest.mock('../src/resolveGitDir') +jest.unmock('execa') + +describe('runAll', () => { + it('should throw when not in a git directory', async () => { + resolveGitDir.mockImplementationOnce(async () => null) + await expect(runAll({})).rejects.toThrowErrorMatchingSnapshot() + }) +})