diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 089863ba5f5e..7151330e720d 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -357,7 +357,7 @@ module.exports = { files: [ 'scripts/*', 'packages/*/__benchmarks__/test.js', - 'packages/jest-cli/src/init/index.ts', + 'packages/create-jest/src/runCreate.ts', 'packages/jest-repl/src/cli/runtime-cli.ts', ], rules: { diff --git a/CHANGELOG.md b/CHANGELOG.md index 655628f438dd..0ce2bc5c5d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[create-jest]` Add `npm init` / `yarn create` initialiser for Jest projects ([#14465](https://github.com/jestjs/jest/pull/14453)) + ### Fixes - `[jest-snapshot]` Allow for strings as well as template literals in inline snapshots ([#14465](https://github.com/jestjs/jest/pull/14465)) @@ -13,6 +15,8 @@ ### Chore & Maintenance +- `[jest-cli]` Move internal config initialisation logic to the `create-jest` package ([#14465](https://github.com/jestjs/jest/pull/14453)) + ## 29.6.4 ### Fixes diff --git a/README.md b/README.md index ba462358a145..8dc4a0b4e02f 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ If you'd like to learn more about running `jest` through the command line, take Based on your project, Jest will ask you a few questions and will create a basic configuration file with a short description for each option: ```bash -jest --init +yarn create jest ``` ### Using Babel diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 04ac8182d165..49643ff8ef0d 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -67,8 +67,8 @@ If you'd like to learn more about running `jest` through the command line, take Based on your project, Jest will ask you a few questions and will create a basic configuration file with a short description for each option: -```bash -jest --init +```bash npm2yarn +npm init jest@latest ``` ### Using Babel diff --git a/package.json b/package.json index 2d382797aeee..1ba3f3ddbbb5 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "test": "yarn lint && yarn jest", "typecheck": "yarn typecheck:examples && yarn typecheck:tests", "typecheck:examples": "tsc -p examples/angular --noEmit && tsc -p examples/expect-extend --noEmit && tsc -p examples/typescript --noEmit", - "typecheck:tests": "tsc -b packages/{babel-jest,babel-plugin-jest-hoist,diff-sequences,expect,expect-utils,jest-circus,jest-cli,jest-config,jest-console,jest-snapshot,jest-util,jest-validate,jest-watcher,jest-worker,pretty-format}/**/__tests__", + "typecheck:tests": "tsc -b packages/{babel-jest,babel-plugin-jest-hoist,create-jest,diff-sequences,expect,expect-utils,jest-circus,jest-cli,jest-config,jest-console,jest-snapshot,jest-util,jest-validate,jest-watcher,jest-worker,pretty-format}/**/__tests__", "verify-old-ts": "node ./scripts/verifyOldTs.mjs", "verify-pnp": "node ./scripts/verifyPnP.mjs", "watch": "yarn build:js && node ./scripts/watch.mjs", diff --git a/packages/create-jest/.npmignore b/packages/create-jest/.npmignore new file mode 100644 index 000000000000..bb9fdb98bae7 --- /dev/null +++ b/packages/create-jest/.npmignore @@ -0,0 +1,8 @@ +**/__mocks__/** +**/__tests__/** +__typetests__ +src +tsconfig.json +tsconfig.tsbuildinfo +api-extractor.json +.eslintcache diff --git a/packages/create-jest/README.md b/packages/create-jest/README.md new file mode 100644 index 000000000000..312a0a817ff5 --- /dev/null +++ b/packages/create-jest/README.md @@ -0,0 +1,11 @@ +# create-jest + +> Getting started with Jest with a single command + +```bash +npm init jest@latest +# Or for Yarn +yarn create jest +# Or for pnpm +pnpm create jest +``` diff --git a/packages/create-jest/bin/create-jest.js b/packages/create-jest/bin/create-jest.js new file mode 100755 index 000000000000..58c8758edb32 --- /dev/null +++ b/packages/create-jest/bin/create-jest.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +require('..').runCLI(); diff --git a/packages/create-jest/package.json b/packages/create-jest/package.json new file mode 100644 index 000000000000..9daa812dda0d --- /dev/null +++ b/packages/create-jest/package.json @@ -0,0 +1,42 @@ +{ + "name": "create-jest", + "description": "Create a new Jest project", + "version": "29.6.4", + "repository": { + "type": "git", + "url": "https://github.com/jestjs/jest.git", + "directory": "packages/create-jest" + }, + "license": "MIT", + "bin": "./bin/create-jest.js", + "main": "./build/index.js", + "types": "./build/index.d.ts", + "exports": { + ".": { + "types": "./build/index.d.ts", + "default": "./build/index.js" + }, + "./package.json": "./package.json", + "./bin/create-jest": "./bin/create-jest.js" + }, + "dependencies": { + "@jest/types": "workspace:^", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "workspace:^", + "jest-util": "workspace:^", + "prompts": "^2.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@types/exit": "^0.1.30", + "@types/graceful-fs": "^4.1.3", + "@types/prompts": "^2.0.1" + } +} diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-cjs/jest.config.cjs b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-cjs/jest.config.cjs similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-cjs/jest.config.cjs rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-cjs/jest.config.cjs diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-cjs/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-cjs/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-cjs/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-cjs/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-js/jest.config.js b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-js/jest.config.js similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-js/jest.config.js rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-js/jest.config.js diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-js/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-js/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-js/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-js/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-json/jest.config.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-json/jest.config.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-json/jest.config.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-json/jest.config.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-json/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-json/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-json/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-json/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-mjs/jest.config.mjs b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-mjs/jest.config.mjs similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-mjs/jest.config.mjs rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-mjs/jest.config.mjs diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-mjs/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-mjs/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-mjs/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-mjs/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-ts/jest.config.ts b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-ts/jest.config.ts similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-ts/jest.config.ts rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-ts/jest.config.ts diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-ts/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-ts/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-file-ts/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-file-ts/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-in-package-json/package.json b/packages/create-jest/src/__tests__/__fixtures__/has-jest-config-in-package-json/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/has-jest-config-in-package-json/package.json rename to packages/create-jest/src/__tests__/__fixtures__/has-jest-config-in-package-json/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/no-package-json/index.js b/packages/create-jest/src/__tests__/__fixtures__/no-package-json/index.js similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/no-package-json/index.js rename to packages/create-jest/src/__tests__/__fixtures__/no-package-json/index.js diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/only-package-json/package.json b/packages/create-jest/src/__tests__/__fixtures__/only-package-json/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/only-package-json/package.json rename to packages/create-jest/src/__tests__/__fixtures__/only-package-json/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/test-generated-jest-config-ts/package.json b/packages/create-jest/src/__tests__/__fixtures__/test-generated-jest-config-ts/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/test-generated-jest-config-ts/package.json rename to packages/create-jest/src/__tests__/__fixtures__/test-generated-jest-config-ts/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/test-script-configured/package.json b/packages/create-jest/src/__tests__/__fixtures__/test-script-configured/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/test-script-configured/package.json rename to packages/create-jest/src/__tests__/__fixtures__/test-script-configured/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/type-module/package.json b/packages/create-jest/src/__tests__/__fixtures__/type-module/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/type-module/package.json rename to packages/create-jest/src/__tests__/__fixtures__/type-module/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/typescript-in-dependencies/package.json b/packages/create-jest/src/__tests__/__fixtures__/typescript-in-dependencies/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/typescript-in-dependencies/package.json rename to packages/create-jest/src/__tests__/__fixtures__/typescript-in-dependencies/package.json diff --git a/packages/jest-cli/src/init/__tests__/__fixtures__/typescript-in-dev-dependencies/package.json b/packages/create-jest/src/__tests__/__fixtures__/typescript-in-dev-dependencies/package.json similarity index 100% rename from packages/jest-cli/src/init/__tests__/__fixtures__/typescript-in-dev-dependencies/package.json rename to packages/create-jest/src/__tests__/__fixtures__/typescript-in-dev-dependencies/package.json diff --git a/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap b/packages/create-jest/src/__tests__/__snapshots__/init.test.ts.snap similarity index 100% rename from packages/jest-cli/src/init/__tests__/__snapshots__/init.test.ts.snap rename to packages/create-jest/src/__tests__/__snapshots__/init.test.ts.snap diff --git a/packages/jest-cli/src/init/__tests__/__snapshots__/modifyPackageJson.test.ts.snap b/packages/create-jest/src/__tests__/__snapshots__/modifyPackageJson.test.ts.snap similarity index 100% rename from packages/jest-cli/src/init/__tests__/__snapshots__/modifyPackageJson.test.ts.snap rename to packages/create-jest/src/__tests__/__snapshots__/modifyPackageJson.test.ts.snap diff --git a/packages/jest-cli/src/init/__tests__/init.test.ts b/packages/create-jest/src/__tests__/init.test.ts similarity index 88% rename from packages/jest-cli/src/init/__tests__/init.test.ts rename to packages/create-jest/src/__tests__/init.test.ts index 30a5769d1be1..38bb1b747226 100644 --- a/packages/jest-cli/src/init/__tests__/init.test.ts +++ b/packages/create-jest/src/__tests__/init.test.ts @@ -10,7 +10,7 @@ import * as path from 'path'; import {writeFileSync} from 'graceful-fs'; import * as prompts from 'prompts'; import {constants} from 'jest-config'; -import init from '../'; +import {runCreate} from '../runCreate'; const {JEST_CONFIG_EXT_ORDER} = constants; @@ -44,7 +44,7 @@ describe('init', () => { it('should return the default configuration (an empty config)', async () => { jest.mocked(prompts).mockResolvedValueOnce({}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfigFilename = jest.mocked(writeFileSync).mock.calls[0][0]; @@ -71,7 +71,7 @@ describe('init', () => { it('should generate empty config with mjs extension', async () => { jest.mocked(prompts).mockResolvedValueOnce({}); - await init(resolveFromFixture('type-module')); + await runCreate(resolveFromFixture('type-module')); const writtenJestConfigFilename = jest.mocked(writeFileSync).mock.calls[0][0]; @@ -93,7 +93,7 @@ describe('init', () => { it('should create configuration for {clearMocks: true}', async () => { jest.mocked(prompts).mockResolvedValueOnce({clearMocks: true}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -107,7 +107,7 @@ describe('init', () => { it('should create configuration for {coverage: true}', async () => { jest.mocked(prompts).mockResolvedValueOnce({coverage: true}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -124,7 +124,7 @@ describe('init', () => { it('should create configuration for {coverageProvider: "babel"}', async () => { jest.mocked(prompts).mockResolvedValueOnce({coverageProvider: 'babel'}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -138,7 +138,7 @@ describe('init', () => { it('should create configuration for {coverageProvider: "v8"}', async () => { jest.mocked(prompts).mockResolvedValueOnce({coverageProvider: 'v8'}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -152,7 +152,7 @@ describe('init', () => { it('should create configuration for {environment: "jsdom"}', async () => { jest.mocked(prompts).mockResolvedValueOnce({environment: 'jsdom'}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -165,7 +165,7 @@ describe('init', () => { it('should create configuration for {environment: "node"}', async () => { jest.mocked(prompts).mockResolvedValueOnce({environment: 'node'}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenJestConfig = jest.mocked(writeFileSync).mock.calls[0][1]; const evaluatedConfig = eval(writtenJestConfig as string) as Record< @@ -178,7 +178,7 @@ describe('init', () => { it('should create package.json with configured test command when {scripts: true}', async () => { jest.mocked(prompts).mockResolvedValueOnce({scripts: true}); - await init(resolveFromFixture('only-package-json')); + await runCreate(resolveFromFixture('only-package-json')); const writtenPackageJson = jest.mocked(writeFileSync).mock.calls[0][1]; const parsedPackageJson = JSON.parse(writtenPackageJson as string) as { @@ -196,7 +196,7 @@ describe('init', () => { expect.assertions(1); try { - await init(resolveFromFixture('no-package-json')); + await runCreate(resolveFromFixture('no-package-json')); } catch (error) { expect((error as Error).message).toMatch( 'Could not find a "package.json" file in', @@ -215,7 +215,9 @@ describe('init', () => { .mockResolvedValueOnce({continue: true}) .mockResolvedValueOnce({}); - await init(resolveFromFixture(`has-jest-config-file-${extension}`)); + await runCreate( + resolveFromFixture(`has-jest-config-file-${extension}`), + ); expect(jest.mocked(prompts).mock.calls[0][0]).toMatchSnapshot(); @@ -230,7 +232,9 @@ describe('init', () => { it('user answered with "No"', async () => { jest.mocked(prompts).mockResolvedValueOnce({continue: false}); - await init(resolveFromFixture(`has-jest-config-file-${extension}`)); + await runCreate( + resolveFromFixture(`has-jest-config-file-${extension}`), + ); // return after first prompt expect(prompts).toHaveBeenCalledTimes(1); }); @@ -243,7 +247,7 @@ describe('init', () => { it('user answered with "Yes"', async () => { jest.mocked(prompts).mockResolvedValueOnce({useTypescript: true}); - await init(resolveFromFixture('test-generated-jest-config-ts')); + await runCreate(resolveFromFixture('test-generated-jest-config-ts')); expect(jest.mocked(prompts).mock.calls[0][0]).toMatchSnapshot(); @@ -264,7 +268,7 @@ describe('init', () => { it('user answered with "No"', async () => { jest.mocked(prompts).mockResolvedValueOnce({useTypescript: false}); - await init(resolveFromFixture('test-generated-jest-config-ts')); + await runCreate(resolveFromFixture('test-generated-jest-config-ts')); const jestConfigFileName = jest.mocked(writeFileSync).mock.calls[0][0]; @@ -282,7 +286,7 @@ describe('init', () => { .mockResolvedValueOnce({continue: true}) .mockResolvedValueOnce({}); - await init(resolveFromFixture('has-jest-config-in-package-json')); + await runCreate(resolveFromFixture('has-jest-config-in-package-json')); expect(jest.mocked(prompts).mock.calls[0][0]).toMatchSnapshot(); @@ -296,7 +300,7 @@ describe('init', () => { it('should not ask "test script question"', async () => { jest.mocked(prompts).mockResolvedValueOnce({}); - await init(resolveFromFixture('test-script-configured')); + await runCreate(resolveFromFixture('test-script-configured')); const questions = jest.mocked(prompts).mock.calls[0][0] as Array< prompts.PromptObject diff --git a/packages/jest-cli/src/init/__tests__/modifyPackageJson.test.ts b/packages/create-jest/src/__tests__/modifyPackageJson.test.ts similarity index 100% rename from packages/jest-cli/src/init/__tests__/modifyPackageJson.test.ts rename to packages/create-jest/src/__tests__/modifyPackageJson.test.ts diff --git a/packages/create-jest/src/__tests__/tsconfig.json b/packages/create-jest/src/__tests__/tsconfig.json new file mode 100644 index 000000000000..dd1bca103251 --- /dev/null +++ b/packages/create-jest/src/__tests__/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../../tsconfig.test.json", + "include": ["./**/*"], + "references": [{"path": "../../"}] +} diff --git a/packages/jest-cli/src/init/errors.ts b/packages/create-jest/src/errors.ts similarity index 85% rename from packages/jest-cli/src/init/errors.ts rename to packages/create-jest/src/errors.ts index 7c6afb886893..2e0d689f525b 100644 --- a/packages/jest-cli/src/init/errors.ts +++ b/packages/create-jest/src/errors.ts @@ -16,10 +16,7 @@ export class NotFoundPackageJsonError extends Error { export class MalformedPackageJsonError extends Error { constructor(packageJsonPath: string) { - super( - `There is malformed json in ${packageJsonPath}\n` + - 'Fix it, and then run "jest --init"', - ); + super(`There is malformed json in ${packageJsonPath}`); this.name = ''; // eslint-disable-next-line @typescript-eslint/no-empty-function Error.captureStackTrace(this, () => {}); diff --git a/packages/jest-cli/src/init/generateConfigFile.ts b/packages/create-jest/src/generateConfigFile.ts similarity index 91% rename from packages/jest-cli/src/init/generateConfigFile.ts rename to packages/create-jest/src/generateConfigFile.ts index 8ac4f93ba3e9..5f774b163091 100644 --- a/packages/jest-cli/src/init/generateConfigFile.ts +++ b/packages/create-jest/src/generateConfigFile.ts @@ -7,13 +7,16 @@ import type {Config} from '@jest/types'; import {defaults, descriptions} from 'jest-config'; +import type {PromptsResults} from './types'; const stringifyOption = ( option: keyof Config.InitialOptions, map: Partial, linePrefix = '', ): string => { - const optionDescription = ` // ${descriptions[option]}`; + const description = descriptions[option]; + const optionDescription = + description != null && description.length > 0 ? ` // ${description}` : ''; const stringifiedObject = `${option}: ${JSON.stringify( map[option], null, @@ -27,7 +30,7 @@ const stringifyOption = ( }; const generateConfigFile = ( - results: Record, + results: PromptsResults, generateEsm = false, ): string => { const {useTypescript, coverage, coverageProvider, clearMocks, environment} = diff --git a/packages/create-jest/src/index.ts b/packages/create-jest/src/index.ts new file mode 100644 index 000000000000..9fd75c54b7c5 --- /dev/null +++ b/packages/create-jest/src/index.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export {runCreate, runCLI} from './runCreate'; diff --git a/packages/jest-cli/src/init/modifyPackageJson.ts b/packages/create-jest/src/modifyPackageJson.ts similarity index 100% rename from packages/jest-cli/src/init/modifyPackageJson.ts rename to packages/create-jest/src/modifyPackageJson.ts diff --git a/packages/jest-cli/src/init/questions.ts b/packages/create-jest/src/questions.ts similarity index 100% rename from packages/jest-cli/src/init/questions.ts rename to packages/create-jest/src/questions.ts diff --git a/packages/jest-cli/src/init/index.ts b/packages/create-jest/src/runCreate.ts similarity index 79% rename from packages/jest-cli/src/init/index.ts rename to packages/create-jest/src/runCreate.ts index 5a9afe346d97..7a8d2fbb0538 100644 --- a/packages/jest-cli/src/init/index.ts +++ b/packages/create-jest/src/runCreate.ts @@ -7,10 +7,11 @@ import * as path from 'path'; import chalk = require('chalk'); +import exit = require('exit'); import * as fs from 'graceful-fs'; import prompts = require('prompts'); import {constants} from 'jest-config'; -import {tryRealpath} from 'jest-util'; +import {clearLine, tryRealpath} from 'jest-util'; import {MalformedPackageJsonError, NotFoundPackageJsonError} from './errors'; import generateConfigFile from './generateConfigFile'; import modifyPackageJson from './modifyPackageJson'; @@ -28,11 +29,28 @@ const { const getConfigFilename = (ext: string) => JEST_CONFIG_BASE_NAME + ext; -export default async function init( - rootDir: string = tryRealpath(process.cwd()), -): Promise { +export async function runCLI(): Promise { + try { + const rootDir = process.argv[2]; + await runCreate(rootDir); + } catch (error: unknown) { + clearLine(process.stderr); + clearLine(process.stdout); + if (error instanceof Error && Boolean(error?.stack)) { + console.error(chalk.red(error.stack)); + } else { + console.error(chalk.red(error)); + } + + exit(1); + throw error; + } +} + +export async function runCreate(rootDir = process.cwd()): Promise { + rootDir = tryRealpath(rootDir); // prerequisite checks - const projectPackageJsonPath: string = path.join(rootDir, PACKAGE_JSON); + const projectPackageJsonPath = path.join(rootDir, PACKAGE_JSON); if (!fs.existsSync(projectPackageJsonPath)) { throw new NotFoundPackageJsonError(rootDir); @@ -45,7 +63,7 @@ export default async function init( try { projectPackageJson = JSON.parse( fs.readFileSync(projectPackageJsonPath, 'utf-8'), - ); + ) as ProjectPackageJson; } catch { throw new MalformedPackageJsonError(projectPackageJsonPath); } @@ -58,7 +76,7 @@ export default async function init( fs.existsSync(path.join(rootDir, getConfigFilename(ext))), ); - if (hasJestProperty || existingJestConfigExt) { + if (hasJestProperty || existingJestConfigExt != null) { const result: {continue: boolean} = await prompts({ initial: true, message: @@ -112,9 +130,10 @@ export default async function init( : JEST_CONFIG_EXT_JS; // Determine Jest config path - const jestConfigPath = existingJestConfigExt - ? getConfigFilename(existingJestConfigExt) - : path.join(rootDir, getConfigFilename(jestConfigFileExt)); + const jestConfigPath = + existingJestConfigExt != null + ? getConfigFilename(existingJestConfigExt) + : path.join(rootDir, getConfigFilename(jestConfigFileExt)); const shouldModifyScripts = results.scripts; diff --git a/packages/jest-cli/src/init/types.ts b/packages/create-jest/src/types.ts similarity index 90% rename from packages/jest-cli/src/init/types.ts rename to packages/create-jest/src/types.ts index 639c22e10da8..07432fab121d 100644 --- a/packages/jest-cli/src/init/types.ts +++ b/packages/create-jest/src/types.ts @@ -17,7 +17,7 @@ export type PromptsResults = { useTypescript: boolean; clearMocks: boolean; coverage: boolean; - coverageProvider: boolean; - environment: boolean; + coverageProvider: string; + environment: string; scripts: boolean; }; diff --git a/packages/create-jest/tsconfig.json b/packages/create-jest/tsconfig.json new file mode 100644 index 000000000000..0f1cd728f463 --- /dev/null +++ b/packages/create-jest/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "include": ["./src/**/*"], + "exclude": ["./**/__tests__/**/*"], + "references": [ + {"path": "../jest-config"}, + {"path": "../jest-types"}, + {"path": "../jest-util"} + ] +} diff --git a/packages/jest-cli/package.json b/packages/jest-cli/package.json index 067c0744072a..e2e641829e9b 100644 --- a/packages/jest-cli/package.json +++ b/packages/jest-cli/package.json @@ -17,20 +17,17 @@ "@jest/test-result": "workspace:^", "@jest/types": "workspace:^", "chalk": "^4.0.0", + "create-jest": "workspace:^", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", "import-local": "^3.0.2", "jest-config": "workspace:^", "jest-util": "workspace:^", "jest-validate": "workspace:^", - "prompts": "^2.0.1", "yargs": "^17.3.1" }, "devDependencies": { "@tsd/typescript": "^5.0.4", "@types/exit": "^0.1.30", - "@types/graceful-fs": "^4.1.3", - "@types/prompts": "^2.0.1", "@types/yargs": "^17.0.8", "tsd-lite": "^0.7.0" }, diff --git a/packages/jest-cli/src/init/__tests__/tsconfig.json b/packages/jest-cli/src/init/__tests__/tsconfig.json deleted file mode 100644 index facea41430cf..000000000000 --- a/packages/jest-cli/src/init/__tests__/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../../../../../tsconfig.test.json", - "include": ["./**/*"], - "references": [{"path": "../../../"}] -} diff --git a/packages/jest-cli/src/run.ts b/packages/jest-cli/src/run.ts index 7322203214ed..6b68efb15df5 100644 --- a/packages/jest-cli/src/run.ts +++ b/packages/jest-cli/src/run.ts @@ -12,11 +12,11 @@ import yargs = require('yargs'); import {getVersion, runCLI} from '@jest/core'; import type {AggregatedResult} from '@jest/test-result'; import type {Config} from '@jest/types'; +import {runCreate} from 'create-jest'; import {deprecationEntries} from 'jest-config'; import {clearLine, tryRealpath} from 'jest-util'; import {validateCLIOptions} from 'jest-validate'; import * as args from './args'; -import init from './init'; export async function run( maybeArgv?: Array, @@ -26,7 +26,7 @@ export async function run( const argv = await buildArgv(maybeArgv); if (argv.init) { - await init(); + await runCreate(); return; } diff --git a/packages/jest-cli/tsconfig.json b/packages/jest-cli/tsconfig.json index 32f96c0f8a77..dabfdb21d4c4 100644 --- a/packages/jest-cli/tsconfig.json +++ b/packages/jest-cli/tsconfig.json @@ -7,6 +7,7 @@ "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], "references": [ + {"path": "../create-jest"}, {"path": "../jest-config"}, {"path": "../jest-core"}, {"path": "../jest-test-result"}, diff --git a/yarn.lock b/yarn.lock index b043cc33f655..20ae53133c8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8021,6 +8021,25 @@ __metadata: languageName: node linkType: hard +"create-jest@workspace:^, create-jest@workspace:packages/create-jest": + version: 0.0.0-use.local + resolution: "create-jest@workspace:packages/create-jest" + dependencies: + "@jest/types": "workspace:^" + "@types/exit": ^0.1.30 + "@types/graceful-fs": ^4.1.3 + "@types/prompts": ^2.0.1 + chalk: ^4.0.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + jest-config: "workspace:^" + jest-util: "workspace:^" + prompts: ^2.0.1 + bin: + create-jest: ./bin/create-jest.js + languageName: unknown + linkType: soft + "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -12396,17 +12415,14 @@ __metadata: "@jest/types": "workspace:^" "@tsd/typescript": ^5.0.4 "@types/exit": ^0.1.30 - "@types/graceful-fs": ^4.1.3 - "@types/prompts": ^2.0.1 "@types/yargs": ^17.0.8 chalk: ^4.0.0 + create-jest: "workspace:^" exit: ^0.1.2 - graceful-fs: ^4.2.9 import-local: ^3.0.2 jest-config: "workspace:^" jest-util: "workspace:^" jest-validate: "workspace:^" - prompts: ^2.0.1 tsd-lite: ^0.7.0 yargs: ^17.3.1 peerDependencies: