From 7043effe5ea741526cec271bc92f5e379d2f0d06 Mon Sep 17 00:00:00 2001 From: Masafumi Koba <473530+ybiquitous@users.noreply.github.com> Date: Fri, 23 Sep 2022 00:42:27 +0900 Subject: [PATCH] Refactor to add test utils New helpers aim to reduce duplication in the test code. --- .gitignore | 1 + lib/__tests__/extends.test.js | 15 ++------ lib/__tests__/ignore.test.js | 34 ++--------------- lib/__tests__/plugins.test.js | 13 ++----- lib/__tests__/postcssPlugin.test.js | 15 ++------ lib/__tests__/processors.test.js | 13 ++----- lib/__tests__/standalone-cache.test.js | 20 +++++----- lib/__tests__/standalone-fix.test.js | 19 +++++----- lib/__tests__/standalone.test.js | 38 ++++--------------- .../stylelintignore.test.js | 13 ++----- lib/testUtils/removeFile.js | 15 ++++++++ lib/testUtils/safeChdir.js | 24 ++++++++++++ 12 files changed, 85 insertions(+), 135 deletions(-) create mode 100644 lib/testUtils/removeFile.js create mode 100644 lib/testUtils/safeChdir.js diff --git a/.gitignore b/.gitignore index 43e22ce62d..2330c495a8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules yarn.lock .vscode/settings.json .idea +tmp/ diff --git a/lib/__tests__/extends.test.js b/lib/__tests__/extends.test.js index e56181c0d1..1336581afb 100644 --- a/lib/__tests__/extends.test.js +++ b/lib/__tests__/extends.test.js @@ -1,9 +1,11 @@ 'use strict'; +const path = require('path'); + +const safeChdir = require('../testUtils/safeChdir'); const configExtendingAnotherExtend = require('./fixtures/config-extending-another-extend.json'); const configExtendingOne = require('./fixtures/config-extending-one'); const configExtendingThreeWithOverride = require('./fixtures/config-extending-three-with-override'); -const path = require('path'); const standalone = require('../standalone'); const fixturesPath = path.join(__dirname, 'fixtures'); @@ -66,16 +68,7 @@ it('extending a config that is overridden', async () => { }); describe('extending a config from process.cwd', () => { - let actualCwd; - - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(__dirname); - }); - - afterAll(() => { - process.chdir(actualCwd); - }); + safeChdir(__dirname); it('works', async () => { const linted = await standalone({ diff --git a/lib/__tests__/ignore.test.js b/lib/__tests__/ignore.test.js index c9bf330f2c..5fc699b230 100644 --- a/lib/__tests__/ignore.test.js +++ b/lib/__tests__/ignore.test.js @@ -5,10 +5,13 @@ const path = require('path'); const NoFilesFoundError = require('../utils/noFilesFoundError'); const AllFilesIgnoredError = require('../utils/allFilesIgnoredError'); const replaceBackslashes = require('../testUtils/replaceBackslashes'); +const safeChdir = require('../testUtils/safeChdir'); const standalone = require('../standalone'); const fixtures = (...elem) => replaceBackslashes(path.join(__dirname, 'fixtures', ...elem)); +safeChdir(__dirname); + test('extending config and ignoreFiles glob ignoring single glob', async () => { const { results } = await standalone({ files: [fixtures('empty-block.css'), fixtures('invalid-hex.css')], @@ -39,10 +42,6 @@ test('extending config and ignoreFiles glob ignoring single glob', async () => { }); test('same as above with no configBasedir, ignore-files path relative to process.cwd', async () => { - const actualCwd = process.cwd(); - - process.chdir(__dirname); - const { results } = await standalone({ files: [fixtures('empty-block.css'), fixtures('invalid-hex.css')], config: { @@ -68,8 +67,6 @@ test('same as above with no configBasedir, ignore-files path relative to process // invalid-hex.css marked as ignored expect(results[1].ignored).toBeTruthy(); - - process.chdir(actualCwd); }); test('same as above with no configBasedir, ignore-files path relative to options.cwd', async () => { @@ -163,9 +160,6 @@ test('extending config with ignoreFiles glob ignoring one by negation', async () test('specified `ignorePath` file ignoring one file', async () => { const files = [fixtures('empty-block.css')]; - const actualCwd = process.cwd(); - - process.chdir(__dirname); await expect( standalone({ @@ -178,15 +172,10 @@ test('specified `ignorePath` file ignoring one file', async () => { ignorePath: [fixtures('ignore.txt')], }), ).rejects.toThrow(AllFilesIgnoredError); // all files ignore - - process.chdir(actualCwd); }); test('specified multiple `ignorePath` to ignore files', async () => { const files = [fixtures('empty-block.css'), fixtures('empty-block-with-disables.css')]; - const actualCwd = process.cwd(); - - process.chdir(__dirname); await expect( standalone({ @@ -199,16 +188,12 @@ test('specified multiple `ignorePath` to ignore files', async () => { ignorePath: [fixtures('ignore.txt'), fixtures('ignore-2.txt')], }), ).rejects.toThrow(AllFilesIgnoredError); // all files ignore - - process.chdir(actualCwd); }); test('specified `ignorePath` file ignoring one file using options.cwd', async () => { const files = [fixtures('empty-block.css')]; const allFilesIgnoredErrorMessage = new AllFilesIgnoredError(files); - process.chdir(__dirname); - await expect( standalone({ files, @@ -224,8 +209,6 @@ test('specified `ignorePath` file ignoring one file using options.cwd', async () }); test('specified `ignorePath` directory, not a file', async () => { - process.chdir(__dirname); - await expect( standalone({ files: [], @@ -238,9 +221,6 @@ test('specified `ignorePath` directory, not a file', async () => { test('specified `ignorePattern` file ignoring one file', async () => { const files = [fixtures('empty-block.css')]; - const actualCwd = process.cwd(); - - process.chdir(__dirname); await expect( standalone({ @@ -253,8 +233,6 @@ test('specified `ignorePattern` file ignoring one file', async () => { ignorePattern: 'fixtures/empty-block.css', }), ).rejects.toThrow(AllFilesIgnoredError); // all files ignore - - process.chdir(actualCwd); }); test('specified `ignorePattern` file ignoring one file using options.cwd', async () => { @@ -277,10 +255,6 @@ test('specified `ignorePattern` file ignoring one file using options.cwd', async test('specified `ignorePattern` file ignoring two files', async () => { const files = [fixtures('empty-block.css'), fixtures('no-syntax-error.css')]; - const actualCwd = process.cwd(); - - process.chdir(__dirname); - await expect( standalone({ files, @@ -292,8 +266,6 @@ test('specified `ignorePattern` file ignoring two files', async () => { ignorePattern: ['fixtures/empty-block.css', 'fixtures/no-syntax-error.css'], }), ).rejects.toThrow(AllFilesIgnoredError); // all files ignore - - process.chdir(actualCwd); }); test('specified `ignorePattern` file ignoring two files using options.cwd', async () => { diff --git a/lib/__tests__/plugins.test.js b/lib/__tests__/plugins.test.js index e862e5d6dc..7d3d61d6d9 100644 --- a/lib/__tests__/plugins.test.js +++ b/lib/__tests__/plugins.test.js @@ -3,6 +3,7 @@ const path = require('path'); const postcss = require('postcss'); const stylelint = require('..'); +const safeChdir = require('../testUtils/safeChdir'); const cssWithFoo = '.foo {}'; @@ -251,7 +252,8 @@ it('plugin with async rule', async () => { }); describe('loading a plugin from process.cwd', () => { - let actualCwd; + safeChdir(__dirname); + let result; const config = { @@ -261,15 +263,6 @@ describe('loading a plugin from process.cwd', () => { }, }; - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(__dirname); - }); - - afterAll(() => { - process.chdir(actualCwd); - }); - beforeEach(async () => { result = await postcss().use(stylelint(config)).process('.foo {}', { from: undefined }); }); diff --git a/lib/__tests__/postcssPlugin.test.js b/lib/__tests__/postcssPlugin.test.js index 58f855b2e2..84597f61fc 100644 --- a/lib/__tests__/postcssPlugin.test.js +++ b/lib/__tests__/postcssPlugin.test.js @@ -1,8 +1,10 @@ 'use strict'; -const configurationError = require('../utils/configurationError'); const path = require('path'); const postcss = require('postcss'); + +const safeChdir = require('../testUtils/safeChdir'); +const configurationError = require('../utils/configurationError'); const postcssPlugin = require('../postcssPlugin'); it('`config` option is `null`', () => { @@ -95,16 +97,7 @@ it('`ignoreFiles` options is not empty and file not ignored', () => { }); describe('stylelintignore', () => { - let actualCwd; - - beforeEach(() => { - actualCwd = process.cwd(); - process.chdir(__dirname); - }); - - afterEach(() => { - process.chdir(actualCwd); - }); + safeChdir(__dirname); it('postcssPlugin with .stylelintignore and file is ignored', () => { const options = { diff --git a/lib/__tests__/processors.test.js b/lib/__tests__/processors.test.js index aa2634c92c..4156bfff90 100644 --- a/lib/__tests__/processors.test.js +++ b/lib/__tests__/processors.test.js @@ -4,6 +4,7 @@ const path = require('path'); const standalone = require('../standalone'); const fixturesPath = path.join(__dirname, './fixtures'); +const safeChdir = require('../testUtils/safeChdir'); describe('processor transforms input and output', () => { let results; @@ -124,17 +125,9 @@ describe('multiple processors', () => { }); describe('loading processors (and extend) from process.cwd', () => { - let actualCwd; - let results; - - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(path.join(__dirname, '..')); - }); + safeChdir(path.join(__dirname, '..')); - afterAll(() => { - process.chdir(actualCwd); - }); + let results; beforeEach(async () => { const code = diff --git a/lib/__tests__/standalone-cache.test.js b/lib/__tests__/standalone-cache.test.js index 156519e61e..e199fe0697 100644 --- a/lib/__tests__/standalone-cache.test.js +++ b/lib/__tests__/standalone-cache.test.js @@ -6,17 +6,10 @@ const { promises: fs, existsSync } = require('fs'); const hash = require('../utils/hash'); const replaceBackslashes = require('../testUtils/replaceBackslashes'); +const removeFile = require('../testUtils/removeFile'); +const safeChdir = require('../testUtils/safeChdir'); const standalone = require('../standalone'); -// NOTE: `fs.rm(file, { force: true })` will be available when we drop the support of older Node versions. -// See -const removeFile = async (filePath) => { - if (existsSync(filePath)) { - await fs.unlink(filePath); - } -}; - -const cwd = process.cwd(); const fixturesPath = path.join(__dirname, 'fixtures'); const invalidFile = path.join(fixturesPath, 'empty-block.css'); const syntaxErrorFile = path.join(fixturesPath, 'syntax_error.css'); @@ -38,8 +31,9 @@ function getConfig(additional = {}) { } describe('standalone cache', () => { - // HACK: The test may fail depending on the timing of the access to the cache file. See #5531 - jest.retryTimes(3); + const cwd = path.join(__dirname, 'tmp', 'standalone-cache'); + + safeChdir(cwd); const expectedCacheFilePath = path.join(cwd, '.stylelintcache'); @@ -162,6 +156,10 @@ describe('standalone cache', () => { }); describe('standalone cache uses cacheLocation', () => { + const cwd = path.join(__dirname, 'tmp', 'standalone-cache-uses-cacheLocation'); + + safeChdir(cwd); + const cacheLocationFile = path.join(fixturesPath, 'cache', '.cachefile'); const cacheLocationDir = path.join(fixturesPath, 'cache'); const expectedCacheFilePath = path.join(cacheLocationDir, `.stylelintcache_${hash(cwd)}`); diff --git a/lib/__tests__/standalone-fix.test.js b/lib/__tests__/standalone-fix.test.js index 983efb85ea..698af9180c 100644 --- a/lib/__tests__/standalone-fix.test.js +++ b/lib/__tests__/standalone-fix.test.js @@ -1,13 +1,14 @@ 'use strict'; -const os = require('os'); const path = require('path'); -const stripIndent = require('common-tags').stripIndent; -const { existsSync, promises: fs } = require('fs'); +const { stripIndent } = require('common-tags'); +const fs = require('fs').promises; +const removeFile = require('../testUtils/removeFile'); const replaceBackslashes = require('../testUtils/replaceBackslashes'); -const standalone = require('../standalone'); +const safeChdir = require('../testUtils/safeChdir'); const uniqueId = require('../testUtils/uniqueId'); +const standalone = require('../standalone'); const fixturesPath = (...elems) => replaceBackslashes(path.join(__dirname, 'fixtures', ...elems)); @@ -150,20 +151,18 @@ it("the indentation rule doesn't fix with scoped stylelint-disable commands", as }); describe('writing fixes to files', () => { - let tmpDir; + safeChdir(path.join(__dirname, 'tmp', `standalone-fix-${uniqueId()}`)); + let tempFile; beforeEach(async () => { - tmpDir = os.tmpdir(); - tempFile = replaceBackslashes(path.join(tmpDir, `stylesheet-${uniqueId()}.css`)); + tempFile = replaceBackslashes(path.join(process.cwd(), 'stylesheet.css')); await fs.copyFile(fixturesPath('fix.css'), tempFile); }); afterEach(async () => { - if (existsSync(tempFile)) { - await fs.unlink(tempFile); - } + await removeFile(tempFile); }); it('overwrites the original file', async () => { diff --git a/lib/__tests__/standalone.test.js b/lib/__tests__/standalone.test.js index adba4eaa09..698d40b312 100644 --- a/lib/__tests__/standalone.test.js +++ b/lib/__tests__/standalone.test.js @@ -1,9 +1,11 @@ 'use strict'; +const path = require('path'); + const configBlockNoEmpty = require('./fixtures/config-block-no-empty'); const NoFilesFoundError = require('../utils/noFilesFoundError'); -const path = require('path'); const replaceBackslashes = require('../testUtils/replaceBackslashes'); +const safeChdir = require('../testUtils/safeChdir'); const standalone = require('../standalone'); const fixturesPath = replaceBackslashes(path.join(__dirname, 'fixtures')); @@ -301,17 +303,9 @@ describe('standalone with different configs per file', () => { }); describe('standalone with config locatable from process.cwd not file', () => { - let actualCwd; - let results; + safeChdir(path.join(__dirname, './fixtures/getConfigForFile/a/b')); - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(path.join(__dirname, './fixtures/getConfigForFile/a/b')); - }); - - afterAll(() => { - process.chdir(actualCwd); - }); + let results; beforeEach(async () => { const data = await standalone({ @@ -360,16 +354,7 @@ describe('standalone with config locatable from options.cwd not file', () => { }); describe('nonexistent codeFilename with loaded config', () => { - let actualCwd; - - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(path.join(__dirname, './fixtures/getConfigForFile/a/b')); - }); - - afterAll(() => { - process.chdir(actualCwd); - }); + safeChdir(path.join(__dirname, './fixtures/getConfigForFile/a/b')); it('does not cause error', async () => { await expect(() => @@ -413,16 +398,7 @@ describe('nonexistent codeFilename with loaded config and options.cwd', () => { }); describe('existing codeFilename for nested config detection', () => { - let actualCwd; - - beforeAll(() => { - actualCwd = process.cwd(); - process.chdir(path.join(__dirname, './fixtures/getConfigForFile')); - }); - - afterAll(() => { - process.chdir(actualCwd); - }); + safeChdir(path.join(__dirname, './fixtures/getConfigForFile')); it('loads config from a nested directory', async () => { const { results } = await standalone({ diff --git a/lib/__tests__/stylelintignore-test/stylelintignore.test.js b/lib/__tests__/stylelintignore-test/stylelintignore.test.js index c97e02a987..af6187dd54 100644 --- a/lib/__tests__/stylelintignore-test/stylelintignore.test.js +++ b/lib/__tests__/stylelintignore-test/stylelintignore.test.js @@ -2,22 +2,15 @@ const path = require('path'); const replaceBackslashes = require('../../testUtils/replaceBackslashes'); +const safeChdir = require('../../testUtils/safeChdir'); const standalone = require('../../standalone'); describe('stylelintignore', () => { - let actualCwd; + safeChdir(__dirname); + let results; const fixturesPath = path.join(__dirname, './fixtures'); - beforeEach(() => { - actualCwd = process.cwd(); - process.chdir(__dirname); - }); - - afterEach(() => { - process.chdir(actualCwd); - }); - describe('standalone with .stylelintignore file ignoring one file', () => { beforeEach(async () => { const data = await standalone({ diff --git a/lib/testUtils/removeFile.js b/lib/testUtils/removeFile.js new file mode 100644 index 0000000000..64a2938fba --- /dev/null +++ b/lib/testUtils/removeFile.js @@ -0,0 +1,15 @@ +const { promises: fs, existsSync } = require('fs'); + +/** + * Remove a file. + * + * @param {string} filePath + * @returns {Promise} + */ +module.exports = async function removeFile(filePath) { + // NOTE: `fs.rm(file, { force: true })` will be available when we drop the support of older Node versions. + // See https://nodejs.org/api/fs.html#fs_fs_rm_path_options_callback + if (existsSync(filePath)) { + await fs.unlink(filePath); + } +}; diff --git a/lib/testUtils/safeChdir.js b/lib/testUtils/safeChdir.js new file mode 100644 index 0000000000..343bc0375e --- /dev/null +++ b/lib/testUtils/safeChdir.js @@ -0,0 +1,24 @@ +const { mkdir } = require('fs').promises; + +/** + * A safe `process.chdir()`. + * + * @param {string} dir - will be created if not exists + * @returns {void} + */ +module.exports = function safeChdir(dir) { + /** @type {string | undefined} */ + let actualCwd; + + // @ts-expect-error - Jest global + beforeEach(async () => { + actualCwd = process.cwd(); + await mkdir(dir, { recursive: true }); + process.chdir(dir); + }); + + // @ts-expect-error - Jest global + afterEach(() => { + if (actualCwd) process.chdir(actualCwd); + }); +};