From b5bbcabdc19d803c1a3796071471b988affbbecd Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 15 May 2022 12:02:20 +0300 Subject: [PATCH 01/11] feat: expose JestConfig type --- docs/Configuration.md | 1493 ++++++++++++++++----- e2e/__tests__/tsIntegration.test.ts | 160 +++ jest.config.ci.mjs | 1 + jest.config.mjs | 2 +- jest.config.ts.mjs | 1 + packages/jest/__typetests__/jest.test.ts | 14 + packages/jest/__typetests__/tsconfig.json | 12 + packages/jest/package.json | 5 + packages/jest/src/index.ts | 4 + packages/jest/tsconfig.json | 6 +- yarn.lock | 3 + 11 files changed, 1396 insertions(+), 305 deletions(-) create mode 100644 packages/jest/__typetests__/jest.test.ts create mode 100644 packages/jest/__typetests__/tsconfig.json diff --git a/docs/Configuration.md b/docs/Configuration.md index f0c971fb9c24..1f0a6840847f 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -3,83 +3,112 @@ id: configuration title: Configuring Jest --- -Jest's configuration can be defined in the `package.json` file of your project, or through a `jest.config.js`, or `jest.config.ts` file or through the `--config ` option. If you'd like to use your `package.json` to store Jest's config, the `"jest"` key should be used on the top level so Jest will know how to find your settings: +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; -```json -{ - "name": "my-project", - "jest": { - "verbose": true - } -} -``` +The Jest philosophy is to work great by default, but sometimes you just need more configuration power. -Or through JavaScript: +It is recommended to define the configuration in a dedicated JavaScript, TypeScript or JSON file. The file will be discovered automatically, if it is named `jest.config.js|ts|mjs|cjs|json`. You can use [`--config`](CLI.md#--configpath) flag to pass an explicit path to the file. -```js title="jest.config.js" -// Sync object -/** @type {import('@jest/types').Config.InitialOptions} */ +:::note + +Keep in mind that the resulting configuration object must always be JSON-serializable. + +::: + +The configuration file should simply export an object or a function returning an object: + + + + +```js +/** @type {import('jest').JestConfig} */ const config = { verbose: true, }; module.exports = config; - -// Or async function -module.exports = async () => { - return { - verbose: true, - }; -}; ``` -Or through TypeScript (if `ts-node` is installed): + + + -```ts title="jest.config.ts" -import type {Config} from '@jest/types'; +```ts +import type {JestConfig} from 'jest'; -// Sync object -const config: Config.InitialOptions = { +const config: JestConfig = { verbose: true, }; -export default config; -// Or async function -export default async (): Promise => { - return { - verbose: true, - }; -}; +export default config; ``` -Please keep in mind that the resulting configuration must be JSON-serializable. + + + +:::tip -When using the `--config` option, the JSON file must not contain a "jest" key: +To read TypeScript configuration files Jest requires [`ts-node`](https://github.com/TypeStrong/ts-node). Make sure it is installed in your project. -```json +::: + +The configuration also can be stored in a JSON file as a plain object: + +```json title="jest.config.json" { "bail": 1, "verbose": true } ``` -## Options +Alternatively Jest's configuration can be defined through the `"jest"` key in the `package.json` of your project: -These options let you control Jest's behavior in your `package.json` file. The Jest philosophy is to work great by default, but sometimes you just need more configuration power. +```json title="package.json" +{ + "name": "my-project", + "jest": { + "verbose": true + } +} +``` + +## Options -### Defaults +You can retrieve Jest's defaults from `jest-config` to extend them if needed: -You can retrieve Jest's default options to expand them if needed: + + -```js title="jest.config.js" +```js const {defaults} = require('jest-config'); -module.exports = { - // ... - moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx'], - // ... + +/** @type {import('jest').JestConfig} */ +const config = { + moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; +import {defaults} from 'jest-config'; + +const config: JestConfig = { + moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts'], }; + +export default config; ``` + + + import TOCInline from '@theme/TOCInline'; @@ -98,15 +127,12 @@ Example: ```js title="utils.js" export default { - authorize: () => { - return 'token'; - }, + authorize: () => 'token', isAuthorized: secret => secret === 'wizard', }; ``` -```js -//__tests__/automocking.test.js +```js title="__tests__/automock.test.js" import utils from '../utils'; test('if utils mocked automatically', () => { @@ -172,18 +198,43 @@ Default: `undefined` An array of [glob patterns](https://github.com/micromatch/micromatch) indicating a set of files for which coverage information should be collected. If a file matches the specified glob pattern, coverage information will be collected for it even if no tests exist for this file and it's never required in the test suite. -Example: + + -```json -{ - "collectCoverageFrom": [ - "**/*.{js,jsx}", - "!**/node_modules/**", - "!**/vendor/**" - ] -} +```js +/** @type {import('jest').JestConfig} */ +const config = { + collectCoverageFrom: [ + '**/*.{js,jsx}', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + collectCoverageFrom: [ + '**/*.{js,jsx}', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +export default config; ``` + + + This will collect coverage information for all the files inside the project's `rootDir`, except the ones that match `**/node_modules/**` or `**/vendor/**`. :::tip @@ -250,12 +301,35 @@ Setting this option overwrites the default values. Add `"text"` or `"text-summar Additional options can be passed using the tuple form. For example, you may hide coverage report lines for all fully-covered files: -```json -{ - "coverageReporters": ["clover", "json", "lcov", ["text", {"skipFull": true}]] -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + coverageReporters: ['clover', 'json', 'lcov', ['text', {skipFull: true}]], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + coverageReporters: ['clover', 'json', 'lcov', ['text', {skipFull: true}]], +}; + +export default config; ``` + + + For more information about the options object shape refer to `CoverageReporterWithOptions` type in the [type definitions](https://github.com/facebook/jest/tree/main/packages/jest-types/src/Config.ts). ### `coverageThreshold` \[object] @@ -266,55 +340,122 @@ This will be used to configure minimum threshold enforcement for coverage result For example, with the following configuration jest will fail if there is less than 80% branch, line, and function coverage, or if there are more than 10 uncovered statements: -```json -{ - ... - "jest": { - "coverageThreshold": { - "global": { - "branches": 80, - "functions": 80, - "lines": 80, - "statements": -10 - } - } - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: -10, + }, + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: -10, + }, + }, +}; + +export default config; ``` + + + If globs or paths are specified alongside `global`, coverage data for matching paths will be subtracted from overall coverage and thresholds will be applied independently. Thresholds for globs are applied to all files matching the glob. If the file specified by path is not found, an error is returned. For example, with the following configuration: -```json -{ - ... - "jest": { - "coverageThreshold": { - "global": { - "branches": 50, - "functions": 50, - "lines": 50, - "statements": 50 - }, - "./src/components/": { - "branches": 40, - "statements": 40 - }, - "./src/reducers/**/*.js": { - "statements": 90 - }, - "./src/api/very-important-module.js": { - "branches": 100, - "functions": 100, - "lines": 100, - "statements": 100 - } - } - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + coverageThreshold: { + global: { + branches: 50, + functions: 50, + lines: 50, + statements: 50, + }, + './src/components/': { + branches: 40, + statements: 40, + }, + './src/reducers/**/*.js': { + statements: 90, + }, + './src/api/very-important-module.js': { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + coverageThreshold: { + global: { + branches: 50, + functions: 50, + lines: 50, + statements: 50, + }, + './src/components/': { + branches: 40, + statements: 40, + }, + './src/reducers/**/*.js': { + statements: 90, + }, + './src/api/very-important-module.js': { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; + +export default config; ``` + + + Jest will fail if: - The `./src/components` directory has less than 40% branch or statement coverage. @@ -355,26 +496,73 @@ That module can also contain a `getCacheKey` function to generate a cache key to default: `undefined` -Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. Here are sample valid values. +Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. + + + ```js -module.exports = { +/** @type {import('jest').JestConfig} */ +const config = { + displayName: 'CLIENT', +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { displayName: 'CLIENT', }; + +export default config; ``` -or + + + +Alternatively, an object with the properties `name` and `color` can be passed. This allows for a custom configuration of the background color of the displayName. `displayName` defaults to white when its value is a string. Jest uses [`chalk`](https://github.com/chalk/chalk) to provide the color. As such, all of the valid options for colors supported by `chalk` are also supported by Jest. + + + ```js -module.exports = { +/** @type {import('jest').JestConfig} */ +const config = { + displayName: { + name: 'CLIENT', + color: 'blue', + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { displayName: { name: 'CLIENT', color: 'blue', }, }; + +export default config; ``` -As a secondary option, an object with the properties `name` and `color` can be passed. This allows for a custom configuration of the background color of the displayName. `displayName` defaults to white when its value is a string. Jest uses [chalk](https://github.com/chalk/chalk) to provide the color. As such, all of the valid options for colors supported by chalk are also supported by jest. + + ### `errorOnDeprecated` \[boolean] @@ -388,21 +576,41 @@ Default: `[]` Jest will run `.mjs` and `.js` files with nearest `package.json`'s `type` field set to `module` as ECMAScript Modules. If you have any other files that should run with native ESM, you need to specify their file extension here. + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + extensionsToTreatAsEsm: ['.ts'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + extensionsToTreatAsEsm: ['.ts'], +}; + +export default config; +``` + + + + :::caution Jest's ESM support is still experimental, see [its docs for more details](ECMAScriptModules.md). ::: -```json -{ - ... - "jest": { - "extensionsToTreatAsEsm": [".ts"] - } -} -``` - ### `fakeTimers` \[object] Default: `{}` @@ -411,15 +619,41 @@ The fake timers may be useful when a piece of code sets a long timeout that we d This option provides the default configuration of fake timers for all tests. Calling `jest.useFakeTimers()` in a test file will use these options or will override them if a configuration object is passed. For example, you can tell Jest to keep the original implementation of `process.nextTick()` and adjust the limit of recursive timers that will be run: -```json -{ - "fakeTimers": { - "doNotFake": ["nextTick"], - "timerLimit": 1000 - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + fakeTimers: { + doNotFake: ['nextTick'], + timerLimit: 1000, + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + fakeTimers: { + doNotFake: ['nextTick'], + timerLimit: 1000, + }, +}; + +export default config; ``` + + + ```js title="fakeTime.test.js" // install fake timers for this file using the options from Jest configuration jest.useFakeTimers(); @@ -432,19 +666,44 @@ test('increase the limit of recursive timers for this and following tests', () = :::tip -Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests: +Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: -```json -{ - "fakeTimers": { - "enableGlobally": true - } -} -``` + + -::: +```js +/** @type {import('jest').JestConfig} */ +const config = { + fakeTimers: { + enableGlobally: true, + }, +}; -Configuration options: +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + fakeTimers: { + enableGlobally: true, + }, +}; + +export default config; +``` + + + + +::: + +Configuration options: ```ts type FakeableAPI = @@ -494,15 +753,41 @@ type ModernFakeTimersConfig = { For some reason you might have to use legacy implementation of fake timers. Here is how to enable it globally (additional options are not supported): -```json -{ - "fakeTimers": { - "enableGlobally": true, - "legacyFakeTimers": true - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + fakeTimers: { + enableGlobally: true, + legacyFakeTimers: true, + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + fakeTimers: { + enableGlobally: true, + legacyFakeTimers: true, + }, +}; + +export default config; ``` + + + ::: ### `forceCoverageMatch` \[array<string>] @@ -527,15 +812,35 @@ if (process.env.NODE_ENV === 'test') { You can collect coverage from those files with setting `forceCoverageMatch`. -```json -{ - ... - "jest": { - "forceCoverageMatch": ["**/*.t.js"] - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + forceCoverageMatch: ['**/*.t.js'], +}; + +module.exports = config; ``` + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + forceCoverageMatch: ['**/*.t.js'], +}; + +export default config; +``` + + + + ### `globals` \[object] Default: `{}` @@ -544,17 +849,39 @@ A set of global variables that need to be available in all test environments. For example, the following would create a global `__DEV__` variable set to `true` in all test environments: -```json -{ - ... - "jest": { - "globals": { - "__DEV__": true - } - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + globals: { + __DEV__: true, + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + globals: { + __DEV__: true, + }, +}; + +export default config; ``` + + + Note that, if you specify a global reference value (like an object or array) here, and some code mutates that value in the midst of running a test, that mutation will _not_ be persisted across test runs for other test files. In addition, the `globals` object must be json-serializable, so it can't be used to specify global functions. For that, you should use `setupFiles`. ### `globalSetup` \[string] @@ -671,13 +998,71 @@ A number limiting the number of tests that are allowed to run at the same time w Specifies the maximum number of workers the worker-pool will spawn for running tests. In single run mode, this defaults to the number of the cores available on your machine minus one for the main thread. In watch mode, this defaults to half of the available cores on your machine to ensure Jest is unobtrusive and does not grind your machine to a halt. It may be useful to adjust this in resource limited environments like CIs but the defaults should be adequate for most use-cases. -For environments with variable CPUs available, you can use percentage based configuration: `"maxWorkers": "50%"` +For environments with variable CPUs available, you can use percentage based configuration: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + maxWorkers: '50%', +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + maxWorkers: '50%', +}; + +export default config; +``` + + + ### `moduleDirectories` \[array<string>] Default: `["node_modules"]` -An array of directory names to be searched recursively up from the requiring module's location. Setting this option will _override_ the default, if you wish to still search `node_modules` for packages include it along with any other options: `["node_modules", "bower_components"]` +An array of directory names to be searched recursively up from the requiring module's location. Setting this option will _override_ the default, if you wish to still search `node_modules` for packages include it along with any other options: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + moduleDirectories: ['node_modules', 'bower_components'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + moduleDirectories: ['node_modules', 'bower_components'], +}; + +export default config; +``` + + + ### `moduleFileExtensions` \[array<string>] @@ -699,23 +1084,53 @@ Use `` string token to refer to [`rootDir`](#rootdir-string) value if y Additionally, you can substitute captured regex groups using numbered backreferences. -Example: + + -```json -{ - "moduleNameMapper": { - "^image![a-zA-Z0-9$_-]+$": "GlobalImageStub", - "^[./a-zA-Z0-9$_-]+\\.png$": "/RelativeImageStub.js", - "module_name_(.*)": "/substituted_module_$1.js", - "assets/(.*)": [ - "/images/$1", - "/photos/$1", - "/recipes/$1" - ] - } -} +```js +/** @type {import('jest').JestConfig} */ +const config = { + moduleNameMapper: { + '^image![a-zA-Z0-9$_-]+$': 'GlobalImageStub', + '^[./a-zA-Z0-9$_-]+\\.png$': '/RelativeImageStub.js', + 'module_name_(.*)': '/substituted_module_$1.js', + 'assets/(.*)': [ + '/images/$1', + '/photos/$1', + '/recipes/$1', + ], + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + moduleNameMapper: { + '^image![a-zA-Z0-9$_-]+$': 'GlobalImageStub', + '^[./a-zA-Z0-9$_-]+\\.png$': '/RelativeImageStub.js', + 'module_name_(.*)': '/substituted_module_$1.js', + 'assets/(.*)': [ + '/images/$1', + '/photos/$1', + '/recipes/$1', + ], + }, +}; + +export default config; ``` + + + The order in which the mappings are defined matters. Patterns are checked one by one until one fits. The most specific rule should be listed first. This is true for arrays of module names as well. :::info @@ -730,13 +1145,71 @@ Default: `[]` An array of regexp pattern strings that are matched against all module paths before those paths are to be considered 'visible' to the module loader. If a given module's path matches any of the patterns, it will not be `require()`-able in the test environment. -These pattern strings match against the full path. Use the `` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. Example: `["/build/"]`. +These pattern strings match against the full path. Use the `` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + modulePathIgnorePatterns: ['/build/'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + modulePathIgnorePatterns: ['/build/'], +}; + +export default config; +``` + + + ### `modulePaths` \[array<string>] Default: `[]` -An alternative API to setting the `NODE_PATH` env variable, `modulePaths` is an array of absolute paths to additional locations to search when resolving modules. Use the `` string token to include the path to your project's root directory. Example: `["/app/"]`. +An alternative API to setting the `NODE_PATH` env variable, `modulePaths` is an array of absolute paths to additional locations to search when resolving modules. Use the `` string token to include the path to your project's root directory. + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + modulePaths: ['/app/'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + modulePaths: ['/app/'], +}; + +export default config; +``` + + + ### `notify` \[boolean] @@ -779,22 +1252,66 @@ A preset that is used as a base for Jest's configuration. A preset should point For example, this preset `foo-bar/jest-preset.js` will be configured as follows: + + + ```js -/** @type { import('@jest/types').Config.InitialOptions } */ -module.exports = { +/** @type {import('jest').JestConfig} */ +const config = { + preset: 'foo-bar', +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { preset: 'foo-bar', }; + +export default config; ``` -Presets may also be relative to filesystem paths. + + + +Presets may also be relative to filesystem paths: + + + ```js -/** @type { import('@jest/types').Config.InitialOptions } */ -module.exports = { +/** @type {import('jest').JestConfig} */ +const config = { preset: './node_modules/foo-bar/jest-preset.js', }; + +module.exports = config; ``` + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + preset: './node_modules/foo-bar/jest-preset.js', +}; + +export default config; +``` + + + + :::info Note that if you also have specified [`rootDir`](#rootdir-string) that the resolution of this file will be relative to that root directory. @@ -813,85 +1330,238 @@ Default: `undefined` When the `projects` configuration is provided with an array of paths or glob patterns, Jest will run tests in all of the specified projects at the same time. This is great for monorepos or when working on multiple projects at the same time. -```json -{ - "projects": ["", "/examples/*"] -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + projects: ['', '/examples/*'], +}; + +module.exports = config; ``` + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + projects: ['', '/examples/*'], +}; + +export default config; +``` + + + + This example configuration will run Jest in the root directory as well as in every folder in the examples directory. You can have an unlimited amount of projects running in the same Jest instance. The projects feature can also be used to run multiple configurations or multiple [runners](#runner-string). For this purpose, you can pass an array of configuration objects. For example, to run both tests and ESLint (via [jest-runner-eslint](https://github.com/jest-community/jest-runner-eslint)) in the same invocation of Jest: -```json -{ - "projects": [ + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + projects: [ { - "displayName": "test" + displayName: 'test', }, { - "displayName": "lint", - "runner": "jest-runner-eslint", - "testMatch": ["/**/*.js"] - } - ] -} + displayName: 'lint', + runner: 'jest-runner-eslint', + testMatch: ['/**/*.js'], + }, + ], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + projects: [ + { + displayName: 'test', + }, + { + displayName: 'lint', + runner: 'jest-runner-eslint', + testMatch: ['/**/*.js'], + }, + ], +}; + +export default config; ``` + + + :::tip When using multi-project runner, it's recommended to add a `displayName` for each project. This will show the `displayName` of a project next to its tests. -::: +::: + +### `reporters` \[array<moduleName | \[moduleName, options]>] + +Default: `undefined` + +Use this configuration option to add reporters to Jest. It must be a list of reporter names, additional options can be passed to a reporter using the tuple form: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + reporters: [ + 'default', + ['/custom-reporter.js', {banana: 'yes', pineapple: 'no'}], + ], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + reporters: [ + 'default', + ['/custom-reporter.js', {banana: 'yes', pineapple: 'no'}], + ], +}; + +export default config; +``` + + + + +#### Default Reporter + +If custom reporters are specified, the default Jest reporter will be overridden. If you wish to keep it, `'default'` must be passed as a reporters name: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + reporters: [ + 'default', + ['jest-junit', {outputDirectory: 'reports', outputName: 'report.xml'}], + ], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + reporters: [ + 'default', + ['jest-junit', {outputDirectory: 'reports', outputName: 'report.xml'}], + ], +}; + +export default config; +``` + + + + +#### GitHub Actions Reporter + +If included in the list, the built-in GitHub Actions Reporter will annotate changed files with test failure messages: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + reporters: ['default', 'github-actions'], +}; + +module.exports = config; +``` + + -### `reporters` \[array<moduleName | \[moduleName, options]>] + -Default: `undefined` +```ts +import type {JestConfig} from 'jest'; -Use this configuration option to add reporters to Jest. It must be a list of reporter names, additional options can be passed to a reporter using the tuple form: +const config: JestConfig = { + reporters: ['default', 'github-actions'], +}; -```json -{ - "reporters": [ - "default", - ["/custom-reporter.js", {"banana": "yes", "pineapple": "no"}] - ] -} +export default config; ``` -#### Default Reporter + + -If custom reporters are specified, the default Jest reporter will be overridden. If you wish to keep it, `'default'` must be passed as a reporters name: +#### Summary Reporter -```json -{ - "reporters": [ - "default", - ["jest-junit", {"outputDirectory": "reports", "outputName": "report.xml"}] - ] -} -``` +Summary reporter prints out summary of all tests. It is a part of default reporter, hence it will be enabled if `'default'` is included in the list. For instance, you might want to use it as stand-alone reporter instead of the default one, or together with [Silent Reporter](https://github.com/rickhanlonii/jest-silent-reporter): -#### GitHub Actions Reporter + + -If included in the list, the built-in GitHub Actions Reporter will annotate changed files with test failure messages: +```js +/** @type {import('jest').JestConfig} */ +const config = { + reporters: ['jest-silent-reporter', 'summary'], +}; -```json -{ - "reporters": ["default", "github-actions"] -} +module.exports = config; ``` -#### Summary Reporter + -Summary reporter prints out summary of all tests. It is a part of default reporter, hence it will be enabled if `'default'` is included in the list. For instance, you might want to use it as stand-alone reporter instead of the default one, or together with [Silent Reporter](https://github.com/rickhanlonii/jest-silent-reporter): + -```json -{ - "reporters": ["jest-silent-reporter", "summary"] -} +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + reporters: ['jest-silent-reporter', 'summary'], +}; + +export default config; ``` + + + #### Custom Reporters :::tip @@ -981,13 +1651,7 @@ The `defaultResolver` passed as an option is the Jest default resolver which mig ::: -For example, if you want to respect Browserify's [`"browser"` field](https://github.com/browserify/browserify-handbook/blob/master/readme.markdown#browser-field), you can use the following configuration: - -```json -{ - "resolver": "/resolver.js" -} -``` +For example, if you want to respect Browserify's [`"browser"` field](https://github.com/browserify/browserify-handbook/blob/master/readme.markdown#browser-field), you can use the following resolver: ```js title="resolver.js" const browserResolve = require('browser-resolve'); @@ -995,6 +1659,37 @@ const browserResolve = require('browser-resolve'); module.exports = browserResolve.sync; ``` +And add it to Jest configuration: + + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + resolver: '/resolver.js', +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + resolver: '/resolver.js', +}; + +export default config; +``` + + + + By combining `defaultResolver` and `packageFilter` we can implement a `package.json` "pre-processor" that allows us to change how the default resolver will resolve modules. For example, imagine we want to use the field `"module"` if it is present, otherwise fallback to `"main"`: ```js @@ -1096,15 +1791,35 @@ Test files run inside a [vm](https://nodejs.org/api/vm.html), which slows calls For example, if your tests call `Math` often, you can pass it by setting `sandboxInjectedGlobals`. -```json -{ - ... - "jest": { - "sandboxInjectedGlobals": ["Math"] - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + sandboxInjectedGlobals: ['Math'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + sandboxInjectedGlobals: ['Math'], +}; + +export default config; ``` + + + :::note This option has no effect if you use [native ESM](ECMAScriptModules.md). @@ -1140,12 +1855,35 @@ afterEach(() => { }); ``` + + + ```js -module.exports = { +/** @type {import('jest').JestConfig} */ +const config = { setupFilesAfterEnv: ['/setup-jest.js'], }; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + setupFilesAfterEnv: ['/setup-matchers.js'], +}; + +export default config; ``` + + + ### `slowTestThreshold` \[number] Default: `5` @@ -1158,19 +1896,40 @@ Default: `undefined` Allows overriding specific snapshot formatting options documented in the [pretty-format readme](https://www.npmjs.com/package/pretty-format#usage-with-options), with the exceptions of `compareKeys` and `plugins`. For example, this config would have the snapshot formatter not print a prefix for "Object" and "Array": -```json -{ - "jest": { - "snapshotFormat": { - "printBasicPrototype": false - } - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + snapshotFormat: { + printBasicPrototype: false, + }, +}; + +module.exports = config; ``` + + + + ```ts -import {expect, test} from '@jest/globals'; +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + snapshotFormat: { + printBasicPrototype: false, + }, +}; + +export default config; +``` + + + +```js title="some.test.js" test('does not show prototypes for object and array inline', () => { const object = { array: [{hello: 'Danger'}], @@ -1193,9 +1952,7 @@ Default: `undefined` The path to a module that can resolve test<->snapshot path. This config option lets you customize where Jest stores snapshot files on disk. -Example snapshot resolver module: - -```js +```js title="custom-resolver.js" module.exports = { // resolves from test to snapshot path resolveSnapshotPath: (testPath, snapshotExtension) => @@ -1220,10 +1977,7 @@ A list of paths to snapshot serializer modules Jest should use for snapshot test Jest has default serializers for built-in JavaScript types, HTML elements (Jest 20.0.0+), ImmutableJS (Jest 20.0.0+) and for React elements. See [snapshot test tutorial](TutorialReactNative.md#snapshot-test) for more information. -Example serializer module: - -```js -// my-serializer-module +```js title="custom-serializer.js" module.exports = { serialize(val, config, indentation, depth, refs, printer) { return `Pretty foo: ${printer(val.foo)}`; @@ -1237,17 +1991,37 @@ module.exports = { `printer` is a function that serializes a value using existing plugins. -To use `my-serializer-module` as a serializer, configuration would be as follows: +Add `custom-serializer` to your Jest configuration: -```json -{ - ... - "jest": { - "snapshotSerializers": ["my-serializer-module"] - } -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + snapshotSerializers: ['path/to/custom-serializer.js'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + snapshotSerializers: ['path/to/custom-serializer.js'], +}; + +export default config; ``` + + + Finally tests would look as follows: ```js @@ -1544,11 +2318,9 @@ Both `sort` and `shard` may optionally return a `Promise`. ::: -Example: - -Sort test path alphabetically. +For example, you may sort test paths alphabetically: -```js title="testSequencer.js" +```js title="custom-sequencer.js" const Sequencer = require('@jest/test-sequencer').default; class CustomSequencer extends Sequencer { @@ -1581,14 +2353,37 @@ class CustomSequencer extends Sequencer { module.exports = CustomSequencer; ``` -Use it in your Jest config file like this: +Add `custom-sequencer` to your Jest configuration: -```json -{ - "testSequencer": "path/to/testSequencer.js" -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + testSequencer: 'path/to/custom-sequencer.js', +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + testSequencer: 'path/to/custom-sequencer.js', +}; + +export default config; ``` + + + ### `testTimeout` \[number] Default: `5000` @@ -1611,13 +2406,41 @@ Keep in mind that a transformer only runs once per file unless the file has chan Remember to include the default `babel-jest` transformer explicitly, if you wish to use it alongside with additional code preprocessors: -```json -"transform": { - "\\.[jt]sx?$": "babel-jest", - "\\.css$": "some-css-transformer", -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + transform: { + '\\.[jt]sx?$': 'babel-jest', + '\\.css$': 'some-css-transformer', + }, +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + transform: { + '\\.[jt]sx?$': 'babel-jest', + '\\.css$': 'some-css-transformer', + }, +}; + +export default config; ``` + + + ::: ### `transformIgnorePatterns` \[array<string>] @@ -1628,29 +2451,76 @@ An array of regexp pattern strings that are matched against all source file path Providing regexp patterns that overlap with each other may result in files not being transformed that you expected to be transformed. For example: -```json -{ - "transformIgnorePatterns": ["/node_modules/(?!(foo|bar)/)", "/bar/"] -} + + + +```js +/** @type {import('jest').JestConfig} */ +const config = { + transformIgnorePatterns: ['/node_modules/(?!(foo|bar)/)', '/bar/'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + transformIgnorePatterns: ['/node_modules/(?!(foo|bar)/)', '/bar/'], +}; + +export default config; ``` + + + The first pattern will match (and therefore not transform) files inside `/node_modules` except for those in `/node_modules/foo/` and `/node_modules/bar/`. The second pattern will match (and therefore not transform) files inside any path with `/bar/` in it. With the two together, files in `/node_modules/bar/` will not be transformed because it does match the second pattern, even though it was excluded by the first. Sometimes it happens (especially in React Native or TypeScript projects) that 3rd party modules are published as untranspiled code. Since all files inside `node_modules` are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors. To overcome this, you may use `transformIgnorePatterns` to allow transpiling such modules. You'll find a good example of this use case in [React Native Guide](/docs/tutorial-react-native#transformignorepatterns-customization). These pattern strings match against the full path. Use the `` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. -Example: + + -```json -{ - "transformIgnorePatterns": [ - "/bower_components/", - "/node_modules/" - ] -} +```js +/** @type {import('jest').JestConfig} */ +const config = { + transformIgnorePatterns: [ + '/bower_components/', + '/node_modules/', + ], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + transformIgnorePatterns: [ + '/bower_components/', + '/node_modules/', + ], +}; + +export default config; ``` + + + ### `unmockedModulePathPatterns` \[array<string>] Default: `[]` @@ -1677,14 +2547,35 @@ These patterns match against the full path. Use the `` string token to Even if nothing is specified here, the watcher will ignore changes to the version control folders (.git, .hg). Other hidden files and directories, i.e. those that begin with a dot (`.`), are watched by default. Remember to escape the dot when you add them to `watchPathIgnorePatterns` as it is a special RegExp character. -Example: + + -```json -{ - "watchPathIgnorePatterns": ["/\\.tmp/", "/bar/"] -} +```js +/** @type {import('jest').JestConfig} */ +const config = { + watchPathIgnorePatterns: ['/\\.tmp/', '/bar/'], +}; + +module.exports = config; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +const config: JestConfig = { + watchPathIgnorePatterns: ['/\\.tmp/', '/bar/'], +}; + +export default config; ``` + + + ### `watchPlugins` \[array<string | \[string, Object]>] Default: `[]` @@ -1713,13 +2604,9 @@ Whether to use [`watchman`](https://facebook.github.io/watchman/) for file crawl ### `//` \[string] -No default +This option allows comments in `package.json`. Include the comment text as the value of this key: -This option allows comments in `package.json`. Include the comment text as the value of this key anywhere in `package.json`. - -Example: - -```json +```json title="package.json" { "name": "my-project", "jest": { diff --git a/e2e/__tests__/tsIntegration.test.ts b/e2e/__tests__/tsIntegration.test.ts index 7ae2637f256c..0b2699a528b7 100644 --- a/e2e/__tests__/tsIntegration.test.ts +++ b/e2e/__tests__/tsIntegration.test.ts @@ -174,3 +174,163 @@ describe('when `Config` type is imported from "@jest/types"', () => { }); }); }); + +describe('when `JestConfig` type is imported from "jest"', () => { + test('with object config exported from TS file', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {displayName: 'ts-object-config', verbose: true}; + export default config; + `, + 'package.json': '{}', + }); + + const {configs, globalConfig} = getConfig(path.join(DIR)); + + expect(configs).toHaveLength(1); + expect(configs[0].displayName?.name).toBe('ts-object-config'); + expect(globalConfig.verbose).toBe(true); + }); + + test('with function config exported from TS file', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + async function getVerbose() {return true;} + export default async (): Promise => { + const verbose: JestConfig['verbose'] = await getVerbose(); + return {displayName: 'ts-async-function-config', verbose}; + }; + `, + 'package.json': '{}', + }); + + const {configs, globalConfig} = getConfig(path.join(DIR)); + + expect(configs).toHaveLength(1); + expect(configs[0].displayName?.name).toBe('ts-async-function-config'); + expect(globalConfig.verbose).toBe(true); + }); + + test('throws if type errors are encountered', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {testTimeout: '10000'}; + export default config; + `, + 'package.json': '{}', + }); + + const {stderr, exitCode} = runJest(DIR); + + expect(stderr).toMatch( + "jest.config.ts(2,29): error TS2322: Type 'string' is not assignable to type 'number'.", + ); + expect(exitCode).toBe(1); + }); + + test('throws if syntax errors are encountered', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {verbose: true}; + export default get config; + `, + 'package.json': '{}', + }); + + const {stderr, exitCode} = runJest(DIR); + + expect(stderr).toMatch( + "jest.config.ts(3,16): error TS2304: Cannot find name 'get'.", + ); + expect(exitCode).toBe(1); + }); + + // The versions where vm.Module exists and commonjs with "exports" is not broken + onNodeVersions('>=12.16.0', () => { + test('works with object config exported from TS file when package.json#type=module', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {displayName: 'ts-esm-object-config', verbose: true}; + export default config; + `, + 'package.json': '{"type": "module"}', + }); + + const {configs, globalConfig} = getConfig(path.join(DIR)); + + expect(configs).toHaveLength(1); + expect(configs[0].displayName?.name).toBe('ts-esm-object-config'); + expect(globalConfig.verbose).toBe(true); + }); + + test('works with function config exported from TS file when package.json#type=module', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + async function getVerbose() {return true;} + export default async (): Promise => { + const verbose: JestConfig['verbose'] = await getVerbose(); + return {displayName: 'ts-esm-async-function-config', verbose}; + }; + `, + 'package.json': '{"type": "module"}', + }); + + const {configs, globalConfig} = getConfig(path.join(DIR)); + + expect(configs).toHaveLength(1); + expect(configs[0].displayName?.name).toBe('ts-esm-async-function-config'); + expect(globalConfig.verbose).toBe(true); + }); + + test('throws if type errors are encountered when package.json#type=module', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {testTimeout: '10000'}; + export default config; + `, + 'package.json': '{"type": "module"}', + }); + + const {stderr, exitCode} = runJest(DIR); + + expect(stderr).toMatch( + "jest.config.ts(2,29): error TS2322: Type 'string' is not assignable to type 'number'.", + ); + expect(exitCode).toBe(1); + }); + + test('throws if syntax errors are encountered when package.json#type=module', () => { + writeFiles(DIR, { + '__tests__/dummy.test.js': + "test('dummy', () => expect(123).toBe(123));", + 'jest.config.ts': ` + import type {JestConfig} from 'jest'; + const config: JestConfig = {verbose: true}; + export default get config; + `, + 'package.json': '{}', + }); + + const {stderr, exitCode} = runJest(DIR); + + expect(stderr).toMatch( + "jest.config.ts(3,16): error TS2304: Cannot find name 'get'.", + ); + expect(exitCode).toBe(1); + }); + }); +}); diff --git a/jest.config.ci.mjs b/jest.config.ci.mjs index ffba96d753c6..1a9688caf6f2 100644 --- a/jest.config.ci.mjs +++ b/jest.config.ci.mjs @@ -7,6 +7,7 @@ import jestConfigBase from './jest.config.mjs'; +/** @type {import('jest').JestConfig} */ export default { ...jestConfigBase, coverageReporters: ['json'], diff --git a/jest.config.mjs b/jest.config.mjs index 1ba1f96f823e..5317d1805c7a 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -8,7 +8,7 @@ import {createRequire} from 'module'; const require = createRequire(import.meta.url); -/** @type import('@jest/types').Config.InitialOptions */ +/** @type {import('jest').JestConfig} */ export default { collectCoverageFrom: [ '**/packages/*/**/*.js', diff --git a/jest.config.ts.mjs b/jest.config.ts.mjs index 890857922fe9..a83f9a93f021 100644 --- a/jest.config.ts.mjs +++ b/jest.config.ts.mjs @@ -7,6 +7,7 @@ import jestConfigBase from './jest.config.mjs'; +/** @type {import('jest').JestConfig} */ export default { projects: [ { diff --git a/packages/jest/__typetests__/jest.test.ts b/packages/jest/__typetests__/jest.test.ts new file mode 100644 index 000000000000..11e701817b58 --- /dev/null +++ b/packages/jest/__typetests__/jest.test.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {expectType} from 'tsd-lite'; +import type {Config} from '@jest/types'; +import type {JestConfig} from 'jest'; + +declare const config: JestConfig; + +expectType(config); diff --git a/packages/jest/__typetests__/tsconfig.json b/packages/jest/__typetests__/tsconfig.json new file mode 100644 index 000000000000..165ba1343021 --- /dev/null +++ b/packages/jest/__typetests__/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "composite": false, + "noUnusedLocals": false, + "noUnusedParameters": false, + "skipLibCheck": true, + + "types": [] + }, + "include": ["./**/*"] +} diff --git a/packages/jest/package.json b/packages/jest/package.json index 0d7b32ecd020..7538b58966a0 100644 --- a/packages/jest/package.json +++ b/packages/jest/package.json @@ -14,9 +14,14 @@ }, "dependencies": { "@jest/core": "^28.1.0", + "@jest/types": "^28.1.0", "import-local": "^3.0.2", "jest-cli": "^28.1.0" }, + "devDependencies": { + "@tsd/typescript": "~4.6.2", + "tsd-lite": "^0.5.1" + }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, diff --git a/packages/jest/src/index.ts b/packages/jest/src/index.ts index d101fd921a01..60e6e4b29ef2 100644 --- a/packages/jest/src/index.ts +++ b/packages/jest/src/index.ts @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +import type {Config} from '@jest/types'; + export { SearchSource, createTestScheduler, @@ -13,3 +15,5 @@ export { } from '@jest/core'; export {run} from 'jest-cli'; + +export type JestConfig = Config.InitialOptions; diff --git a/packages/jest/tsconfig.json b/packages/jest/tsconfig.json index 21169670d305..454abee9f0e8 100644 --- a/packages/jest/tsconfig.json +++ b/packages/jest/tsconfig.json @@ -5,5 +5,9 @@ "outDir": "build" }, "include": ["./src/**/*"], - "references": [{"path": "../jest-cli"}, {"path": "../jest-core"}] + "references": [ + {"path": "../jest-cli"}, + {"path": "../jest-core"}, + {"path": "../jest-types"} + ] } diff --git a/yarn.lock b/yarn.lock index 050470a7b40c..3c584bce388d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13777,8 +13777,11 @@ __metadata: resolution: "jest@workspace:packages/jest" dependencies: "@jest/core": ^28.1.0 + "@jest/types": ^28.1.0 + "@tsd/typescript": ~4.6.2 import-local: ^3.0.2 jest-cli: ^28.1.0 + tsd-lite: ^0.5.1 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: From 9a85be6171170ea1cf7b75e72773dd7b4e6a871e Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 15 May 2022 13:23:46 +0300 Subject: [PATCH 02/11] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b0e4a8b3327..1530a5a5eb6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest]` Expose `JestConfig` type ([#12848](https://github.com/facebook/jest/pull/12848)) - `[@jest/reporters]` Improve `GitHubActionsReporter`s annotation format ([#12826](https://github.com/facebook/jest/pull/12826)) ### Fixes From a3a008ebf4b9c5d65791941266688a808236650a Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 07:49:40 +0300 Subject: [PATCH 03/11] add async function example --- docs/Configuration.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 1f0a6840847f..5a4ff62da8f3 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -16,7 +16,7 @@ Keep in mind that the resulting configuration object must always be JSON-seriali ::: -The configuration file should simply export an object or a function returning an object: +The configuration file should simply export an object: @@ -47,6 +47,37 @@ export default config; +Or a function returning an object: + + + + +```js +/** @returns {Promise} */ +module.exports = async () => { + return { + verbose: true, + }; +}; +``` + + + + + +```ts +import type {JestConfig} from 'jest'; + +export default async (): Promise => { + return { + verbose: true, + }; +}; +``` + + + + :::tip To read TypeScript configuration files Jest requires [`ts-node`](https://github.com/TypeStrong/ts-node). Make sure it is installed in your project. From 4448af671157bffd5bc58708d17e1170b10f18dd Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 07:51:56 +0300 Subject: [PATCH 04/11] refactor note on defaults --- docs/Configuration.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 5a4ff62da8f3..29599340048e 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -106,6 +106,8 @@ Alternatively Jest's configuration can be defined through the `"jest"` key in th ## Options +:::info + You can retrieve Jest's defaults from `jest-config` to extend them if needed: @@ -116,7 +118,7 @@ const {defaults} = require('jest-config'); /** @type {import('jest').JestConfig} */ const config = { - moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts'], + moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts', 'cts'], }; module.exports = config; @@ -140,6 +142,8 @@ export default config; +::: + import TOCInline from '@theme/TOCInline'; From 7e8e9bc84e7f50fe96e20fe1617492faa064246f Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 07:58:26 +0300 Subject: [PATCH 05/11] rename Config --- docs/Configuration.md | 228 +++++++++++------------ packages/jest/__typetests__/jest.test.ts | 8 +- packages/jest/src/index.ts | 2 +- 3 files changed, 119 insertions(+), 119 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 29599340048e..06108753982a 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -22,7 +22,7 @@ The configuration file should simply export an object: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { verbose: true, }; @@ -35,9 +35,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { verbose: true, }; @@ -53,7 +53,7 @@ Or a function returning an object: ```js -/** @returns {Promise} */ +/** @returns {Promise} */ module.exports = async () => { return { verbose: true, @@ -66,9 +66,9 @@ module.exports = async () => { ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -export default async (): Promise => { +export default async (): Promise => { return { verbose: true, }; @@ -116,7 +116,7 @@ You can retrieve Jest's defaults from `jest-config` to extend them if needed: ```js const {defaults} = require('jest-config'); -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts', 'cts'], }; @@ -129,10 +129,10 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; import {defaults} from 'jest-config'; -const config: JestConfig = { +const config: Config = { moduleFileExtensions: [...defaults.moduleFileExtensions, 'mts'], }; @@ -237,7 +237,7 @@ An array of [glob patterns](https://github.com/micromatch/micromatch) indicating ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { collectCoverageFrom: [ '**/*.{js,jsx}', @@ -254,9 +254,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { collectCoverageFrom: [ '**/*.{js,jsx}', '!**/node_modules/**', @@ -340,7 +340,7 @@ Additional options can be passed using the tuple form. For example, you may hide ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { coverageReporters: ['clover', 'json', 'lcov', ['text', {skipFull: true}]], }; @@ -353,9 +353,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { coverageReporters: ['clover', 'json', 'lcov', ['text', {skipFull: true}]], }; @@ -379,7 +379,7 @@ For example, with the following configuration jest will fail if there is less th ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { coverageThreshold: { global: { @@ -399,9 +399,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { coverageThreshold: { global: { branches: 80, @@ -426,7 +426,7 @@ For example, with the following configuration: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { coverageThreshold: { global: { @@ -459,9 +459,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { coverageThreshold: { global: { branches: 50, @@ -537,7 +537,7 @@ Allows for a label to be printed alongside a test while it is running. This beco ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { displayName: 'CLIENT', }; @@ -550,9 +550,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { displayName: 'CLIENT', }; @@ -568,7 +568,7 @@ Alternatively, an object with the properties `name` and `color` can be passed. T ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { displayName: { name: 'CLIENT', @@ -584,9 +584,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { displayName: { name: 'CLIENT', color: 'blue', @@ -615,7 +615,7 @@ Jest will run `.mjs` and `.js` files with nearest `package.json`'s `type` field ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { extensionsToTreatAsEsm: ['.ts'], }; @@ -628,9 +628,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { extensionsToTreatAsEsm: ['.ts'], }; @@ -658,7 +658,7 @@ This option provides the default configuration of fake timers for all tests. Cal ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { fakeTimers: { doNotFake: ['nextTick'], @@ -674,9 +674,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { fakeTimers: { doNotFake: ['nextTick'], timerLimit: 1000, @@ -707,7 +707,7 @@ Instead of including `jest.useFakeTimers()` in each test file, you can enable fa ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { fakeTimers: { enableGlobally: true, @@ -722,9 +722,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { fakeTimers: { enableGlobally: true, }, @@ -792,7 +792,7 @@ For some reason you might have to use legacy implementation of fake timers. Here ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { fakeTimers: { enableGlobally: true, @@ -808,9 +808,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { fakeTimers: { enableGlobally: true, legacyFakeTimers: true, @@ -851,7 +851,7 @@ You can collect coverage from those files with setting `forceCoverageMatch`. ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { forceCoverageMatch: ['**/*.t.js'], }; @@ -864,9 +864,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { forceCoverageMatch: ['**/*.t.js'], }; @@ -888,7 +888,7 @@ For example, the following would create a global `__DEV__` variable set to `true ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { globals: { __DEV__: true, @@ -903,9 +903,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { globals: { __DEV__: true, }, @@ -1039,7 +1039,7 @@ For environments with variable CPUs available, you can use percentage based conf ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { maxWorkers: '50%', }; @@ -1052,9 +1052,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { maxWorkers: '50%', }; @@ -1074,7 +1074,7 @@ An array of directory names to be searched recursively up from the requiring mod ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { moduleDirectories: ['node_modules', 'bower_components'], }; @@ -1087,9 +1087,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { moduleDirectories: ['node_modules', 'bower_components'], }; @@ -1123,7 +1123,7 @@ Additionally, you can substitute captured regex groups using numbered backrefere ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { moduleNameMapper: { '^image![a-zA-Z0-9$_-]+$': 'GlobalImageStub', @@ -1145,9 +1145,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { moduleNameMapper: { '^image![a-zA-Z0-9$_-]+$': 'GlobalImageStub', '^[./a-zA-Z0-9$_-]+\\.png$': '/RelativeImageStub.js', @@ -1186,7 +1186,7 @@ These pattern strings match against the full path. Use the `` string to ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { modulePathIgnorePatterns: ['/build/'], }; @@ -1199,9 +1199,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { modulePathIgnorePatterns: ['/build/'], }; @@ -1221,7 +1221,7 @@ An alternative API to setting the `NODE_PATH` env variable, `modulePaths` is an ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { modulePaths: ['/app/'], }; @@ -1234,9 +1234,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { modulePaths: ['/app/'], }; @@ -1291,7 +1291,7 @@ For example, this preset `foo-bar/jest-preset.js` will be configured as follows: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { preset: 'foo-bar', }; @@ -1304,9 +1304,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { preset: 'foo-bar', }; @@ -1322,7 +1322,7 @@ Presets may also be relative to filesystem paths: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { preset: './node_modules/foo-bar/jest-preset.js', }; @@ -1335,9 +1335,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { preset: './node_modules/foo-bar/jest-preset.js', }; @@ -1369,7 +1369,7 @@ When the `projects` configuration is provided with an array of paths or glob pat ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { projects: ['', '/examples/*'], }; @@ -1382,9 +1382,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { projects: ['', '/examples/*'], }; @@ -1402,7 +1402,7 @@ The projects feature can also be used to run multiple configurations or multiple ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { projects: [ { @@ -1424,9 +1424,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { projects: [ { displayName: 'test', @@ -1461,7 +1461,7 @@ Use this configuration option to add reporters to Jest. It must be a list of rep ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { reporters: [ 'default', @@ -1477,9 +1477,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { reporters: [ 'default', ['/custom-reporter.js', {banana: 'yes', pineapple: 'no'}], @@ -1500,7 +1500,7 @@ If custom reporters are specified, the default Jest reporter will be overridden. ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { reporters: [ 'default', @@ -1516,9 +1516,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { reporters: [ 'default', ['jest-junit', {outputDirectory: 'reports', outputName: 'report.xml'}], @@ -1539,7 +1539,7 @@ If included in the list, the built-in GitHub Actions Reporter will annotate chan ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { reporters: ['default', 'github-actions'], }; @@ -1552,9 +1552,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { reporters: ['default', 'github-actions'], }; @@ -1572,7 +1572,7 @@ Summary reporter prints out summary of all tests. It is a part of default report ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { reporters: ['jest-silent-reporter', 'summary'], }; @@ -1585,9 +1585,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { reporters: ['jest-silent-reporter', 'summary'], }; @@ -1700,7 +1700,7 @@ And add it to Jest configuration: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { resolver: '/resolver.js', }; @@ -1713,9 +1713,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { resolver: '/resolver.js', }; @@ -1830,7 +1830,7 @@ For example, if your tests call `Math` often, you can pass it by setting `sandbo ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { sandboxInjectedGlobals: ['Math'], }; @@ -1843,9 +1843,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { sandboxInjectedGlobals: ['Math'], }; @@ -1894,7 +1894,7 @@ afterEach(() => { ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { setupFilesAfterEnv: ['/setup-jest.js'], }; @@ -1907,9 +1907,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { setupFilesAfterEnv: ['/setup-matchers.js'], }; @@ -1935,7 +1935,7 @@ Allows overriding specific snapshot formatting options documented in the [pretty ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { snapshotFormat: { printBasicPrototype: false, @@ -1950,9 +1950,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { snapshotFormat: { printBasicPrototype: false, }, @@ -2032,7 +2032,7 @@ Add `custom-serializer` to your Jest configuration: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { snapshotSerializers: ['path/to/custom-serializer.js'], }; @@ -2045,9 +2045,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { snapshotSerializers: ['path/to/custom-serializer.js'], }; @@ -2394,7 +2394,7 @@ Add `custom-sequencer` to your Jest configuration: ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { testSequencer: 'path/to/custom-sequencer.js', }; @@ -2407,9 +2407,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { testSequencer: 'path/to/custom-sequencer.js', }; @@ -2445,7 +2445,7 @@ Remember to include the default `babel-jest` transformer explicitly, if you wish ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { transform: { '\\.[jt]sx?$': 'babel-jest', @@ -2461,9 +2461,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { transform: { '\\.[jt]sx?$': 'babel-jest', '\\.css$': 'some-css-transformer', @@ -2490,7 +2490,7 @@ Providing regexp patterns that overlap with each other may result in files not b ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { transformIgnorePatterns: ['/node_modules/(?!(foo|bar)/)', '/bar/'], }; @@ -2503,9 +2503,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { transformIgnorePatterns: ['/node_modules/(?!(foo|bar)/)', '/bar/'], }; @@ -2525,7 +2525,7 @@ These pattern strings match against the full path. Use the `` string to ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { transformIgnorePatterns: [ '/bower_components/', @@ -2541,9 +2541,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { transformIgnorePatterns: [ '/bower_components/', '/node_modules/', @@ -2586,7 +2586,7 @@ Even if nothing is specified here, the watcher will ignore changes to the versio ```js -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ const config = { watchPathIgnorePatterns: ['/\\.tmp/', '/bar/'], }; @@ -2599,9 +2599,9 @@ module.exports = config; ```ts -import type {JestConfig} from 'jest'; +import type {Config} from 'jest'; -const config: JestConfig = { +const config: Config = { watchPathIgnorePatterns: ['/\\.tmp/', '/bar/'], }; diff --git a/packages/jest/__typetests__/jest.test.ts b/packages/jest/__typetests__/jest.test.ts index 11e701817b58..82ed8518fe3e 100644 --- a/packages/jest/__typetests__/jest.test.ts +++ b/packages/jest/__typetests__/jest.test.ts @@ -6,9 +6,9 @@ */ import {expectType} from 'tsd-lite'; -import type {Config} from '@jest/types'; -import type {JestConfig} from 'jest'; +import type {Config as ConfigTypes} from '@jest/types'; +import type {Config} from 'jest'; -declare const config: JestConfig; +declare const config: Config; -expectType(config); +expectType(config); diff --git a/packages/jest/src/index.ts b/packages/jest/src/index.ts index 60e6e4b29ef2..389dfc649555 100644 --- a/packages/jest/src/index.ts +++ b/packages/jest/src/index.ts @@ -16,4 +16,4 @@ export { export {run} from 'jest-cli'; -export type JestConfig = Config.InitialOptions; +export type Config = Config.InitialOptions; From 49917f8cef7c8b2c5b09cbcde0aac3ac63cdba53 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 08:02:31 +0300 Subject: [PATCH 06/11] fix ts-integration test --- e2e/__tests__/tsIntegration.test.ts | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/e2e/__tests__/tsIntegration.test.ts b/e2e/__tests__/tsIntegration.test.ts index 0b2699a528b7..953ee0aaa5ab 100644 --- a/e2e/__tests__/tsIntegration.test.ts +++ b/e2e/__tests__/tsIntegration.test.ts @@ -175,13 +175,13 @@ describe('when `Config` type is imported from "@jest/types"', () => { }); }); -describe('when `JestConfig` type is imported from "jest"', () => { +describe('when `Config` type is imported from "jest"', () => { test('with object config exported from TS file', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {displayName: 'ts-object-config', verbose: true}; + import type {Config} from 'jest'; + const config: Config = {displayName: 'ts-object-config', verbose: true}; export default config; `, 'package.json': '{}', @@ -198,10 +198,10 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; + import type {Config} from 'jest'; async function getVerbose() {return true;} - export default async (): Promise => { - const verbose: JestConfig['verbose'] = await getVerbose(); + export default async (): Promise => { + const verbose: Config['verbose'] = await getVerbose(); return {displayName: 'ts-async-function-config', verbose}; }; `, @@ -219,8 +219,8 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {testTimeout: '10000'}; + import type {Config} from 'jest'; + const config: Config = {testTimeout: '10000'}; export default config; `, 'package.json': '{}', @@ -229,7 +229,7 @@ describe('when `JestConfig` type is imported from "jest"', () => { const {stderr, exitCode} = runJest(DIR); expect(stderr).toMatch( - "jest.config.ts(2,29): error TS2322: Type 'string' is not assignable to type 'number'.", + "jest.config.ts(2,25): error TS2322: Type 'string' is not assignable to type 'number'.", ); expect(exitCode).toBe(1); }); @@ -238,8 +238,8 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {verbose: true}; + import type {Config} from 'jest'; + const config: Config = {verbose: true}; export default get config; `, 'package.json': '{}', @@ -259,8 +259,8 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {displayName: 'ts-esm-object-config', verbose: true}; + import type {Config} from 'jest'; + const config: Config = {displayName: 'ts-esm-object-config', verbose: true}; export default config; `, 'package.json': '{"type": "module"}', @@ -277,10 +277,10 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; + import type {Config} from 'jest'; async function getVerbose() {return true;} - export default async (): Promise => { - const verbose: JestConfig['verbose'] = await getVerbose(); + export default async (): Promise => { + const verbose: Config['verbose'] = await getVerbose(); return {displayName: 'ts-esm-async-function-config', verbose}; }; `, @@ -298,8 +298,8 @@ describe('when `JestConfig` type is imported from "jest"', () => { writeFiles(DIR, { '__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {testTimeout: '10000'}; + import type {Config} from 'jest'; + const config: Config = {testTimeout: '10000'}; export default config; `, 'package.json': '{"type": "module"}', @@ -308,7 +308,7 @@ describe('when `JestConfig` type is imported from "jest"', () => { const {stderr, exitCode} = runJest(DIR); expect(stderr).toMatch( - "jest.config.ts(2,29): error TS2322: Type 'string' is not assignable to type 'number'.", + "jest.config.ts(2,25): error TS2322: Type 'string' is not assignable to type 'number'.", ); expect(exitCode).toBe(1); }); @@ -318,8 +318,8 @@ describe('when `JestConfig` type is imported from "jest"', () => { '__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));", 'jest.config.ts': ` - import type {JestConfig} from 'jest'; - const config: JestConfig = {verbose: true}; + import type {Config} from 'jest'; + const config: Config = {verbose: true}; export default get config; `, 'package.json': '{}', From 2034d078bdd7074f227807ed9d3d6a46f6670e12 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 08:06:16 +0300 Subject: [PATCH 07/11] fix config files --- jest.config.ci.mjs | 2 +- jest.config.mjs | 2 +- jest.config.ts.mjs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jest.config.ci.mjs b/jest.config.ci.mjs index 1a9688caf6f2..02a7e520853d 100644 --- a/jest.config.ci.mjs +++ b/jest.config.ci.mjs @@ -7,7 +7,7 @@ import jestConfigBase from './jest.config.mjs'; -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ export default { ...jestConfigBase, coverageReporters: ['json'], diff --git a/jest.config.mjs b/jest.config.mjs index 5317d1805c7a..28c68e7890e4 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -8,7 +8,7 @@ import {createRequire} from 'module'; const require = createRequire(import.meta.url); -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ export default { collectCoverageFrom: [ '**/packages/*/**/*.js', diff --git a/jest.config.ts.mjs b/jest.config.ts.mjs index a83f9a93f021..52a1f64cd0ca 100644 --- a/jest.config.ts.mjs +++ b/jest.config.ts.mjs @@ -7,7 +7,7 @@ import jestConfigBase from './jest.config.mjs'; -/** @type {import('jest').JestConfig} */ +/** @type {import('jest').Config} */ export default { projects: [ { From a041c8ae849dbc0bba8428aa39838c047a62841b Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 08:07:46 +0300 Subject: [PATCH 08/11] baseConfig --- jest.config.ci.mjs | 4 ++-- jest.config.ts.mjs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jest.config.ci.mjs b/jest.config.ci.mjs index 02a7e520853d..2b2f36983f5e 100644 --- a/jest.config.ci.mjs +++ b/jest.config.ci.mjs @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import jestConfigBase from './jest.config.mjs'; +import baseConfig from './jest.config.mjs'; /** @type {import('jest').Config} */ export default { - ...jestConfigBase, + ...baseConfig, coverageReporters: ['json'], reporters: [ 'github-actions', diff --git a/jest.config.ts.mjs b/jest.config.ts.mjs index 52a1f64cd0ca..d58bd155e20e 100644 --- a/jest.config.ts.mjs +++ b/jest.config.ts.mjs @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import jestConfigBase from './jest.config.mjs'; +import baseConfig from './jest.config.mjs'; /** @type {import('jest').Config} */ export default { @@ -15,7 +15,7 @@ export default { color: 'blue', name: 'ts-integration', }, - modulePathIgnorePatterns: jestConfigBase.modulePathIgnorePatterns, + modulePathIgnorePatterns: baseConfig.modulePathIgnorePatterns, roots: ['/e2e/__tests__'], testMatch: ['/e2e/__tests__/ts*'], }, @@ -24,7 +24,7 @@ export default { color: 'blue', name: 'type-tests', }, - modulePathIgnorePatterns: jestConfigBase.modulePathIgnorePatterns, + modulePathIgnorePatterns: baseConfig.modulePathIgnorePatterns, roots: ['/packages'], runner: 'jest-runner-tsd', testMatch: ['**/__typetests__/**/*.ts'], From 62ec4166ddf80fad76cf5cea983633d2e7311076 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 17 May 2022 08:17:02 +0300 Subject: [PATCH 09/11] restart CI From fa78b162afd4b0ca3bfb594363d4af51ac1309f3 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 20:26:57 +0300 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Simen Bekkhus --- CHANGELOG.md | 2 +- docs/Configuration.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1530a5a5eb6d..ea6b50006ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features -- `[jest]` Expose `JestConfig` type ([#12848](https://github.com/facebook/jest/pull/12848)) +- `[jest]` Expose `Config` type ([#12848](https://github.com/facebook/jest/pull/12848)) - `[@jest/reporters]` Improve `GitHubActionsReporter`s annotation format ([#12826](https://github.com/facebook/jest/pull/12826)) ### Fixes diff --git a/docs/Configuration.md b/docs/Configuration.md index 06108753982a..b6067a99a508 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -80,7 +80,7 @@ export default async (): Promise => { :::tip -To read TypeScript configuration files Jest requires [`ts-node`](https://github.com/TypeStrong/ts-node). Make sure it is installed in your project. +To read TypeScript configuration files Jest requires [`ts-node`](https://npmjs.com/package/ts-node). Make sure it is installed in your project. ::: From 87e90713a21be02d5e8a871c46d3e9ee08122cfd Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 20:28:35 +0300 Subject: [PATCH 11/11] refactor ConfigTypes --- packages/jest/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest/src/index.ts b/packages/jest/src/index.ts index 389dfc649555..415c7a7ffa47 100644 --- a/packages/jest/src/index.ts +++ b/packages/jest/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {Config} from '@jest/types'; +import type {Config as ConfigTypes} from '@jest/types'; export { SearchSource, @@ -16,4 +16,4 @@ export { export {run} from 'jest-cli'; -export type Config = Config.InitialOptions; +export type Config = ConfigTypes.InitialOptions;