From 552922ea3c9a4713e84de41c0d7ff12ee55218a4 Mon Sep 17 00:00:00 2001 From: ahnpnl Date: Wed, 27 Nov 2024 12:24:29 +0700 Subject: [PATCH] feat: add preset creator functions --- presets/index.d.ts | 2 + presets/index.js | 2 + src/presets/__snapshots__/index.spec.ts.snap | 142 +++++++++++++++- src/presets/create-cjs-preset.ts | 25 +++ src/presets/create-esm-preset.ts | 31 ++++ src/presets/index.spec.ts | 33 +++- src/presets/index.ts | 2 + src/presets/utils.ts | 11 ++ website/docs/getting-started/presets.md | 162 +++++++++++++------ 9 files changed, 355 insertions(+), 55 deletions(-) create mode 100644 src/presets/create-cjs-preset.ts create mode 100644 src/presets/create-esm-preset.ts create mode 100644 src/presets/utils.ts diff --git a/presets/index.d.ts b/presets/index.d.ts index 9cbee83fba..6078ed226b 100644 --- a/presets/index.d.ts +++ b/presets/index.d.ts @@ -18,5 +18,7 @@ declare const _default: { snapshotSerializers: string[]; }; defaultTransformerOptions: import('ts-jest').TsJestTransformerOptions; + createCjsPreset: typeof import('../build/presets').createCjsPreset; + createEsmPreset: typeof import('../build/presets').createEsmPreset; }; export default _default; diff --git a/presets/index.js b/presets/index.js index 6a93171652..c48570134a 100644 --- a/presets/index.js +++ b/presets/index.js @@ -4,4 +4,6 @@ module.exports = { defaults: ngJestPresets.defaultPreset, defaultsESM: ngJestPresets.defaultEsmPreset, defaultTransformerOptions: ngJestPresets.defaultTransformerOptions, + createCjsPreset: ngJestPresets.createCjsPreset, + createEsmPreset: ngJestPresets.createEsmPreset, }; diff --git a/src/presets/__snapshots__/index.spec.ts.snap b/src/presets/__snapshots__/index.spec.ts.snap index c3eefa95c9..0b940a975e 100644 --- a/src/presets/__snapshots__/index.spec.ts.snap +++ b/src/presets/__snapshots__/index.spec.ts.snap @@ -21,12 +21,14 @@ exports[`Jest presets should have the correct types which come from \`ts-jest\` snapshotSerializers: string[]; }; defaultTransformerOptions: import('ts-jest').TsJestTransformerOptions; + createCjsPreset: typeof import('../build/presets').createCjsPreset; + createEsmPreset: typeof import('../build/presets').createEsmPreset; }; export default _default; " `; -exports[`Jest presets should return the correct jest config 1`] = ` +exports[`Jest presets should return jest config with CJS preset creator function with options 1`] = ` { "moduleFileExtensions": [ "ts", @@ -45,6 +47,7 @@ exports[`Jest presets should return the correct jest config 1`] = ` "^.+\\.(ts|js|mjs|html|svg)$": [ "jest-preset-angular", { + "diagnostics": false, "stringifyContentPathRegex": "\\.(html|svg)$", "tsconfig": "/tsconfig.spec.json", }, @@ -56,7 +59,142 @@ exports[`Jest presets should return the correct jest config 1`] = ` } `; -exports[`Jest presets should return the correct jest config 2`] = ` +exports[`Jest presets should return jest config with CJS preset creator function without options 1`] = ` +{ + "moduleFileExtensions": [ + "ts", + "html", + "js", + "json", + "mjs", + ], + "snapshotSerializers": [ + "jest-preset-angular/build/serializers/html-comment", + "jest-preset-angular/build/serializers/ng-snapshot", + "jest-preset-angular/build/serializers/no-ng-attributes", + ], + "testEnvironment": "jsdom", + "transform": { + "^.+\\.(ts|js|mjs|html|svg)$": [ + "jest-preset-angular", + { + "stringifyContentPathRegex": "\\.(html|svg)$", + "tsconfig": "/tsconfig.spec.json", + }, + ], + }, + "transformIgnorePatterns": [ + "node_modules/(?!.*\\.mjs$)", + ], +} +`; + +exports[`Jest presets should return jest config with ESM preset creator function with options 1`] = ` +{ + "extensionsToTreatAsEsm": [ + ".ts", + ], + "moduleFileExtensions": [ + "ts", + "html", + "js", + "json", + "mjs", + ], + "moduleNameMapper": { + "tslib": "tslib/tslib.es6.js", + }, + "snapshotSerializers": [ + "jest-preset-angular/build/serializers/html-comment", + "jest-preset-angular/build/serializers/ng-snapshot", + "jest-preset-angular/build/serializers/no-ng-attributes", + ], + "testEnvironment": "jsdom", + "transform": { + "^.+\\.(ts|js|html|svg)$": [ + "jest-preset-angular", + { + "diagnostics": false, + "stringifyContentPathRegex": "\\.(html|svg)$", + "tsconfig": "/tsconfig.spec.json", + "useESM": true, + }, + ], + }, + "transformIgnorePatterns": [ + "node_modules/(?!tslib)", + ], +} +`; + +exports[`Jest presets should return jest config with ESM preset creator function without options 1`] = ` +{ + "extensionsToTreatAsEsm": [ + ".ts", + ], + "moduleFileExtensions": [ + "ts", + "html", + "js", + "json", + "mjs", + ], + "moduleNameMapper": { + "tslib": "tslib/tslib.es6.js", + }, + "snapshotSerializers": [ + "jest-preset-angular/build/serializers/html-comment", + "jest-preset-angular/build/serializers/ng-snapshot", + "jest-preset-angular/build/serializers/no-ng-attributes", + ], + "testEnvironment": "jsdom", + "transform": { + "^.+\\.(ts|js|html|svg)$": [ + "jest-preset-angular", + { + "stringifyContentPathRegex": "\\.(html|svg)$", + "tsconfig": "/tsconfig.spec.json", + "useESM": true, + }, + ], + }, + "transformIgnorePatterns": [ + "node_modules/(?!tslib)", + ], +} +`; + +exports[`Jest presets should return the correct jest config with legacy preset config 1`] = ` +{ + "moduleFileExtensions": [ + "ts", + "html", + "js", + "json", + "mjs", + ], + "snapshotSerializers": [ + "jest-preset-angular/build/serializers/html-comment", + "jest-preset-angular/build/serializers/ng-snapshot", + "jest-preset-angular/build/serializers/no-ng-attributes", + ], + "testEnvironment": "jsdom", + "transform": { + "^.+\\.(ts|js|mjs|html|svg)$": [ + "jest-preset-angular", + { + "stringifyContentPathRegex": "\\.(html|svg)$", + "tsconfig": "/tsconfig.spec.json", + }, + ], + }, + "transformIgnorePatterns": [ + "node_modules/(?!.*\\.mjs$)", + ], +} +`; + +exports[`Jest presets should return the correct jest config with legacy preset config 2`] = ` { "extensionsToTreatAsEsm": [ ".ts", diff --git a/src/presets/create-cjs-preset.ts b/src/presets/create-cjs-preset.ts new file mode 100644 index 0000000000..32650920c8 --- /dev/null +++ b/src/presets/create-cjs-preset.ts @@ -0,0 +1,25 @@ +import type { Config } from 'jest'; +import type { TsJestTransformerOptions } from 'ts-jest'; + +import { basePresetConfig } from './utils'; + +type CjsPresetType = typeof basePresetConfig & Required>; + +type CjsPresetOptionsType = Omit; + +export const createCjsPreset = (options: CjsPresetOptionsType = {}): CjsPresetType => { + return { + ...basePresetConfig, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + ...options, + }, + ], + }, + }; +}; diff --git a/src/presets/create-esm-preset.ts b/src/presets/create-esm-preset.ts new file mode 100644 index 0000000000..9ab1635f1d --- /dev/null +++ b/src/presets/create-esm-preset.ts @@ -0,0 +1,31 @@ +import type { Config } from 'jest'; +import type { TsJestTransformerOptions } from 'ts-jest'; + +import { basePresetConfig } from './utils'; + +type EsmPresetType = typeof basePresetConfig & + Required>; + +type EsmPresetOptionsType = Omit; + +export const createEsmPreset = (options: EsmPresetOptionsType = {}): EsmPresetType => { + return { + ...basePresetConfig, + extensionsToTreatAsEsm: ['.ts'], + moduleNameMapper: { + tslib: 'tslib/tslib.es6.js', + }, + transformIgnorePatterns: ['node_modules/(?!tslib)'], + transform: { + '^.+\\.(ts|js|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + useESM: true, + ...options, + }, + ], + }, + }; +}; diff --git a/src/presets/index.spec.ts b/src/presets/index.spec.ts index 891297e258..4f7320ecd4 100644 --- a/src/presets/index.spec.ts +++ b/src/presets/index.spec.ts @@ -1,11 +1,38 @@ import fs from 'fs'; import path from 'path'; -import { defaultPreset, defaultEsmPreset } from './'; +import { defaultPreset, defaultEsmPreset, createCjsPreset, createEsmPreset } from './'; describe('Jest presets', () => { - test.each([defaultPreset, defaultEsmPreset])('should return the correct jest config', (preset) => { - expect(preset).toMatchSnapshot(); + test.each([defaultPreset, defaultEsmPreset])( + 'should return the correct jest config with legacy preset config', + (preset) => { + expect(preset).toMatchSnapshot(); + }, + ); + + it('should return jest config with CJS preset creator function without options', () => { + expect(createCjsPreset()).toMatchSnapshot(); + }); + + it('should return jest config with CJS preset creator function with options', () => { + expect( + createCjsPreset({ + diagnostics: false, + }), + ).toMatchSnapshot(); + }); + + it('should return jest config with ESM preset creator function without options', () => { + expect(createEsmPreset()).toMatchSnapshot(); + }); + + it('should return jest config with ESM preset creator function with options', () => { + expect( + createEsmPreset({ + diagnostics: false, + }), + ).toMatchSnapshot(); }); test('should have the correct types which come from `ts-jest`', () => { diff --git a/src/presets/index.ts b/src/presets/index.ts index affd6aa5f2..6ba8710a29 100644 --- a/src/presets/index.ts +++ b/src/presets/index.ts @@ -40,3 +40,5 @@ const defaultEsmPreset = { }; export { defaultPreset, defaultEsmPreset, defaultTransformerOptions }; +export { createCjsPreset } from './create-cjs-preset'; +export { createEsmPreset } from './create-esm-preset'; diff --git a/src/presets/utils.ts b/src/presets/utils.ts new file mode 100644 index 0000000000..e389ee9fe2 --- /dev/null +++ b/src/presets/utils.ts @@ -0,0 +1,11 @@ +import type { Config } from 'jest'; + +import snapshotSerializers from '../serializers'; + +type BasePresetConfig = Required>; + +export const basePresetConfig: BasePresetConfig = { + testEnvironment: 'jsdom', + moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'], + snapshotSerializers, +}; diff --git a/website/docs/getting-started/presets.md b/website/docs/getting-started/presets.md index a202915e40..a16804c62e 100644 --- a/website/docs/getting-started/presets.md +++ b/website/docs/getting-started/presets.md @@ -3,75 +3,147 @@ id: presets title: Presets --- -### The presets +In Jest, **presets** are pre-defined configurations that help streamline and standardize the process of setting up testing environments. +They allow developers to quickly configure Jest with specific transformers, file extensions, and other options. -`jest-preset-angular` comes with 2 presets, covering most of the project's base configuration: +`jest-preset-angular` provides very opinionated presets and based on what we found to be useful. -| Preset name | Description | -| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | -| `jest-preset-angular/presets/default`
or `jest-preset-angular` | TypeScript, JavaScript and HTML files (`js`, `.ts`, `.html`) will be transformed by `jest-preset-angular` to **CommonJS** syntax. | -| `jest-preset-angular/presets/defaults-esm`
| TypeScript, JavaScript and HTML files (`js`, `.ts`, `.html`) will be transformed by `jest-preset-angular` to **ESM** syntax. | +:::important + +The current best practice for using presets is to call one of the utility functions below to create (and optionally extend) presets. Legacy presets are listed at the bottom of the page. -### Basic usage +::: -In most cases, simply setting the `preset` key to the desired preset name in your Jest config should be enough to start -using TypeScript with Jest (assuming you added `jest-preset-angular` to your `devDependencies` of course): +## Functions -```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import TOCInline from '@theme/TOCInline'; + + + +--- + +### `createCjsPreset(options)` + +Create a configuration to process JavaScript/TypeScript/HTML/SVG files (`ts|js|mjs|html|svg`). + +#### Parameters + +- `options` (**OPTIONAL**) + - `tsconfig`: see more at [tsconfig options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/tsconfig) + - `isolatedModules`: see more at [isolatedModules options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/isolatedModules) + - `astTransformers`: see more at [astTransformers options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/astTransformers) + - `diagnostics`: see more at [diagnostics options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/diagnostics) + +#### Returns + +An object contains Jest config: + +```ts +type CjsPresetTransformerOptions = { + tsconfig: string; + stringifyContentPathRegex: string; +}; + +type CjsPresetType = { + testEnvironment: string; + moduleFileExtensions: Array; + snapshotSerializers: Array; + transformIgnorePatterns: Array; + transform: { + '^.+.tsx?$': ['^.+\\.(ts|js|mjs|html|svg)$', CjsPresetTransformerOptions]; + }; +}; +``` + +#### Example: + +```ts title="jest.config.ts" +import presets from 'jest-preset-angular/presets'; import type { Config } from 'jest'; +const presetConfig = presets.createCjsPreset({ + //...options +}); + const jestConfig: Config = { - // [...] - // Replace `jest-preset-angular` with the preset you want to use - // from the above list - preset: 'jest-preset-angular', + ...presetConfig, }; export default jestConfig; ``` -```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +### `createEsmPreset(options)` + +Create a configuration to process JavaScript/TypeScript/HTML/SVG files (`ts|js|html|svg`). + +#### Parameters + +- `options` (**OPTIONAL**) + - `tsconfig`: see more at [tsconfig options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/tsconfig) + - `isolatedModules`: see more at [isolatedModules options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/isolatedModules) + - `astTransformers`: see more at [astTransformers options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/astTransformers) + - `diagnostics`: see more at [diagnostics options page](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/diagnostics) + +#### Returns + +An object contains Jest config: + +```ts +type EsmPresetTransformerOptions = { + tsconfig: string; + stringifyContentPathRegex: string; + useEsm: true; +}; + +type EsmPresetType = { + testEnvironment: string; + moduleFileExtensions: Array; + snapshotSerializers: Array; + transformIgnorePatterns: Array; + transform: { + '^.+.tsx?$': ['^.+\\.(ts|js|html|svg)$', EsmPresetTransformerOptions]; + }; +}; +``` + +#### Example: + +```ts title="jest.config.mts" +import presets from 'jest-preset-angular/presets'; import type { Config } from 'jest'; +const presetConfig = presets.createEsmPreset({ + //...options +}); + const jestConfig: Config = { - // [...] - // Replace `jest-preset-angular` with the preset you want to use - // from the above list - preset: 'jest-preset-angular', + ...presetConfig, }; export default jestConfig; ``` -### Advanced - -All presets come with default `ts-jest` config options. -If you want to override any of the options, you'll need to use the JavaScript version of Jest config, -copy the original options and override the options you need: +### Legacy presets -:::important +:::warning -If you choose to override `transform` in order to point at a specific tsconfig, you will need to make sure that original `ts-jest` -options provided through the default preset are defined to the `transform` section too, otherwise you will get -errors. +`jest-preset-angular` **DON'T RECOMMEND** to use legacy presets because this approach is not flexible to configure Jest configuration. +These legacy presets will be removed in the next major release and users are **HIGHLY RECOMMENDED** to migrate to use the above utility functions. ::: +| Preset name | Description | +| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | +| `jest-preset-angular/presets/default`
or `jest-preset-angular` | TypeScript, JavaScript and HTML files (`js`, `.ts`, `.html`) will be transformed by `jest-preset-angular` to **CommonJS** syntax. | +| `jest-preset-angular/presets/defaults-esm`
| TypeScript, JavaScript and HTML files (`js`, `.ts`, `.html`) will be transformed by `jest-preset-angular` to **ESM** syntax. | + +#### Example + ```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} import type { Config } from 'jest'; -import presets from 'jest-preset-angular/presets'; const jestConfig: Config = { - // [...] - transform: { - '^.+\\.(ts|js|mjs|html|svg)$': [ - 'jest-preset-angular', - { - ...presets.defaultTransformerOptions, - // [...your overriden options] - }, - ], - }, + preset: 'jest-preset-angular', }; export default jestConfig; @@ -79,19 +151,9 @@ export default jestConfig; ```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} import type { Config } from 'jest'; -import presets from 'jest-preset-angular/presets'; const jestConfig: Config = { - // [...] - transform: { - '^.+\\.(ts|js|mjs|html|svg)$': [ - 'jest-preset-angular', - { - ...presets.defaultTransformerOptions, - // [...your overriden options] - }, - ], - }, + preset: 'jest-preset-angular/presets/defaults-esm', }; export default jestConfig;