diff --git a/jest.config.js b/jest.config.js index b7568c554..878a1825a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,11 @@ const config = { collectCoverage: true, - collectCoverageFrom: ['lib/**/*.js'], + collectCoverageFrom: [ + 'lib/**/*.js', + // Avoid ESM import.meta parse error. + // (Can't measure coverage anyway, it's always mocked) + '!lib/resolveConfig.js', + ], moduleDirectories: ['node_modules'], setupFiles: ['./testSetup.js'], snapshotSerializers: ['jest-snapshot-serializer-ansi'], diff --git a/lib/loadConfig.js b/lib/loadConfig.js index 76493447d..8c9b8c55e 100644 --- a/lib/loadConfig.js +++ b/lib/loadConfig.js @@ -6,6 +6,8 @@ import debug from 'debug' import { lilconfig } from 'lilconfig' import YAML from 'yaml' +import { resolveConfig } from './resolveConfig.js' + const debugLog = debug('lint-staged:loadConfig') /** @@ -49,14 +51,6 @@ const loaders = { noExt: yamlParse, } -const resolveConfig = (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } -} - /** * @param {object} options * @param {string} [options.configPath] - Explicit path to a config file diff --git a/lib/resolveConfig.js b/lib/resolveConfig.js new file mode 100644 index 000000000..0b9f357c1 --- /dev/null +++ b/lib/resolveConfig.js @@ -0,0 +1,15 @@ +import { createRequire } from 'module' + +/** + * require() does not exist for ESM, so we must create it to use require.resolve(). + * @see https://nodejs.org/api/module.html#modulecreaterequirefilename + */ +const require = createRequire(import.meta.url) + +export function resolveConfig(configPath) { + try { + return require.resolve(configPath) + } catch { + return configPath + } +} diff --git a/test/index.spec.js b/test/index.spec.js index 004ef7444..81bd5193d 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -28,6 +28,16 @@ jest.mock('url', () => ({ jest.mock('../lib/getStagedFiles') jest.mock('../lib/gitWorkflow') +jest.mock('../lib/resolveConfig', () => ({ + /** Unfortunately necessary due to non-ESM tests. */ + resolveConfig: (configPath) => { + try { + return require.resolve(configPath) + } catch { + return configPath + } + }, +})) jest.mock('../lib/validateOptions', () => ({ validateOptions: jest.fn().mockImplementation(async () => {}), })) diff --git a/test/index2.spec.js b/test/index2.spec.js index 8712feff5..41de135f3 100644 --- a/test/index2.spec.js +++ b/test/index2.spec.js @@ -4,6 +4,17 @@ import { Listr } from 'listr2' import makeConsoleMock from 'consolemock' jest.mock('listr2') +jest.mock('../lib/resolveConfig', () => ({ + /** Unfortunately necessary due to non-ESM tests. */ + resolveConfig: (configPath) => { + try { + return require.resolve(configPath) + } catch { + return configPath + } + }, +})) + jest.mock('../lib/resolveGitRepo') import lintStaged from '../lib/index' diff --git a/test/integration.test.js b/test/integration.test.js index cc9c2da11..d044a3a13 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -7,6 +7,16 @@ import normalize from 'normalize-path' jest.unmock('lilconfig') jest.unmock('execa') +jest.mock('../lib/resolveConfig', () => ({ + /** Unfortunately necessary due to non-ESM tests. */ + resolveConfig: (configPath) => { + try { + return require.resolve(configPath) + } catch { + return configPath + } + }, +})) import { execGit as execGitBase } from '../lib/execGit' import lintStaged from '../lib/index' @@ -88,6 +98,9 @@ describe('lint-staged', () => { const globalConsoleTemp = console +// Tests should be resilient to `git config init.defaultBranch` that is _not_ "master" +let defaultBranchName = 'UNSET' + describe('lint-staged', () => { beforeAll(() => { console = makeConsoleMock() @@ -104,6 +117,10 @@ describe('lint-staged', () => { await appendFile('README.md', '# Test\n') await execGit(['add', 'README.md']) await execGit(['commit', '-m initial commit']) + + if (defaultBranchName === 'UNSET') { + defaultBranchName = await execGit(['rev-parse', '--abbrev-ref', 'HEAD']) + } }) afterEach(async () => { @@ -451,7 +468,7 @@ describe('lint-staged', () => { await gitCommit(fixJsConfig, ['-m commit a']) expect(await readFile('test.js')).toEqual(fileInBranchA) - await execGit(['checkout', 'master']) + await execGit(['checkout', defaultBranchName]) // Create another branch await execGit(['checkout', '-b', 'branch-b']) @@ -461,7 +478,7 @@ describe('lint-staged', () => { expect(await readFile('test.js')).toEqual(fileInBranchBFixed) // Merge first branch - await execGit(['checkout', 'master']) + await execGit(['checkout', defaultBranchName]) await execGit(['merge', 'branch-a']) expect(await readFile('test.js')).toEqual(fileInBranchA) expect(await execGit(['log', '-1', '--pretty=%B'])).toMatch('commit a') @@ -512,7 +529,7 @@ describe('lint-staged', () => { await gitCommit(fixJsConfig, ['-m commit a']) expect(await readFile('test.js')).toEqual(fileInBranchA) - await execGit(['checkout', 'master']) + await execGit(['checkout', defaultBranchName]) // Create another branch await execGit(['checkout', '-b', 'branch-b']) @@ -522,7 +539,7 @@ describe('lint-staged', () => { expect(await readFile('test.js')).toEqual(fileInBranchBFixed) // Merge first branch - await execGit(['checkout', 'master']) + await execGit(['checkout', defaultBranchName]) await execGit(['merge', 'branch-a']) expect(await readFile('test.js')).toEqual(fileInBranchA) expect(await execGit(['log', '-1', '--pretty=%B'])).toMatch('commit a') @@ -1073,7 +1090,7 @@ describe('lintStaged', () => { await execGit(['add', 'test.js'], { cwd }) await expect(execGit(['log', '-1'], { cwd })).rejects.toThrowErrorMatchingInlineSnapshot( - `"fatal: your current branch 'master' does not have any commits yet"` + `"fatal: your current branch '${defaultBranchName}' does not have any commits yet"` ) await gitCommit({ diff --git a/test/loadConfig.spec.js b/test/loadConfig.spec.js index 33272e610..2123012ae 100644 --- a/test/loadConfig.spec.js +++ b/test/loadConfig.spec.js @@ -1,3 +1,14 @@ +jest.mock('../lib/resolveConfig', () => ({ + /** Unfortunately necessary due to non-ESM tests. */ + resolveConfig: (configPath) => { + try { + return require.resolve(configPath) + } catch { + return configPath + } + }, +})) + import { dynamicImport } from '../lib/loadConfig.js' describe('dynamicImport', () => {