From d91ab8e3fe80a0c17fea2571afe2663a777a4dce Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sat, 22 Apr 2023 10:49:43 +0300 Subject: [PATCH] feat(jest-cli): include type definitions to generated config files (#14078) --- CHANGELOG.md | 1 + .../__tests__/__snapshots__/init.test.ts.snap | 412 +++++++++++++++++- .../jest-cli/src/init/__tests__/init.test.ts | 27 +- .../jest-cli/src/init/generateConfigFile.ts | 34 +- 4 files changed, 450 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 404cad490fdd..0fb90714a9e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-cli]` Include type definitions to generated config files ([#14078](https://github.com/facebook/jest/pull/14078)) - `[jest-snapshot]` Support arrays as property matchers ([#14025](https://github.com/facebook/jest/pull/14025)) ### Fixes diff --git a/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap b/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap index 31cca289857e..f28f12ec94ca 100644 --- a/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap @@ -115,13 +115,419 @@ Array [ ] `; +exports[`init project using jest.config.ts ask the user whether he wants to use Typescript or not user answered with "Yes" 2`] = ` +"/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import type {Config} from 'jest'; + +const config: Config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after \`n\` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest", + + // Automatically clear mock calls, instances, contexts and results before every test + // clearMocks: false, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + // coverageProvider: "babel", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\\\.pnp\\\\.[^\\\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default config; +" +`; + +exports[`init project with package.json and no jest config all questions answered with answer: "No" should generate empty config with mjs extension 1`] = ` +"/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +/** @type {import('jest').Config} */ +const config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after \`n\` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest", + + // Automatically clear mock calls, instances, contexts and results before every test + // clearMocks: false, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + // coverageProvider: "babel", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\\\.pnp\\\\.[^\\\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default config; +" +`; + exports[`init project with package.json and no jest config all questions answered with answer: "No" should return the default configuration (an empty config) 1`] = ` -"/* +"/** * For a detailed explanation regarding each configuration property, visit: * https://jestjs.io/docs/configuration */ -module.exports = { +/** @type {import('jest').Config} */ +const config = { // All imported modules in your tests should be mocked automatically // automock: false, @@ -311,6 +717,8 @@ module.exports = { // Whether to use watchman for file crawling // watchman: true, }; + +module.exports = config; " `; diff --git a/packages/jest-cli/src/init/__tests__/init.test.ts b/packages/jest-cli/src/init/__tests__/init.test.ts index a470937f313a..30a5769d1be1 100644 --- a/packages/jest-cli/src/init/__tests__/init.test.ts +++ b/packages/jest-cli/src/init/__tests__/init.test.ts @@ -20,7 +20,7 @@ jest.mock('path', () => ({ sep: '/', })); jest.mock('graceful-fs', () => ({ - ...jest.requireActual('fs'), + ...jest.requireActual('graceful-fs'), writeFileSync: jest.fn(), })); @@ -46,8 +46,13 @@ describe('init', () => { await init(resolveFromFixture('only-package-json')); + const writtenJestConfigFilename = + jest.mocked(writeFileSync).mock.calls[0][0]; const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; + expect(path.basename(writtenJestConfigFilename as string)).toBe( + 'jest.config.js', + ); expect( (writtenJestConfig as string).replace( /\/\/ cacheDirectory: .*,/, @@ -75,11 +80,12 @@ describe('init', () => { expect(path.basename(writtenJestConfigFilename as string)).toBe( 'jest.config.mjs', ); - - expect(typeof writtenJestConfig).toBe('string'); - expect((writtenJestConfig as string).split('\n')[5]).toBe( - 'export default {', - ); + expect( + (writtenJestConfig as string).replace( + /\/\/ cacheDirectory: .*,/, + '// cacheDirectory: "/tmp/jest",', + ), + ).toMatchSnapshot(); }); }); @@ -247,9 +253,12 @@ describe('init', () => { expect(path.basename(jestConfigFileName as string)).toBe( 'jest.config.ts', ); - expect((writtenJestConfig as string).split('\n')[5]).toBe( - 'export default {', - ); + expect( + (writtenJestConfig as string).replace( + /\/\/ cacheDirectory: .*,/, + '// cacheDirectory: "/tmp/jest",', + ), + ).toMatchSnapshot(); }); it('user answered with "No"', async () => { diff --git a/packages/jest-cli/src/init/generateConfigFile.ts b/packages/jest-cli/src/init/generateConfigFile.ts index c96e2055e210..8ac4f93ba3e9 100644 --- a/packages/jest-cli/src/init/generateConfigFile.ts +++ b/packages/jest-cli/src/init/generateConfigFile.ts @@ -23,7 +23,7 @@ const stringifyOption = ( return `${optionDescription}\n${stringifiedObject .split('\n') .map(line => ` ${linePrefix}${line}`) - .join('\n')},\n`; + .join('\n')},`; }; const generateConfigFile = ( @@ -78,22 +78,30 @@ const generateConfigFile = ( } } - const configHeaderMessage = `/* - * For a detailed explanation regarding each configuration property${ - useTypescript ? ' and type check' : '' - }, visit: + const configHeaderMessage = `/** + * For a detailed explanation regarding each configuration property, visit: * https://jestjs.io/docs/configuration */ - `; - return `${ - configHeaderMessage + - (useTypescript || generateEsm - ? 'export default {\n' - : 'module.exports = {\n') + - properties.join('\n') - }};\n`; + const jsDeclaration = `/** @type {import('jest').Config} */ +const config = {`; + + const tsDeclaration = `import type {Config} from 'jest'; + +const config: Config = {`; + + const cjsExport = 'module.exports = config;'; + const esmExport = 'export default config;'; + + return [ + configHeaderMessage, + useTypescript ? tsDeclaration : jsDeclaration, + properties.join('\n\n'), + '};\n', + useTypescript || generateEsm ? esmExport : cjsExport, + '', + ].join('\n'); }; export default generateConfigFile;