From 6d6c214eb19914b37b5c5d5114b7fce34e4cdff0 Mon Sep 17 00:00:00 2001 From: ahnpnl Date: Fri, 10 Jan 2025 13:47:49 +0100 Subject: [PATCH] chore(release): 14.5.0 --- CHANGELOG.md | 20 ++ package.json | 2 +- .../getting-started/installation.md | 164 +++++++++ .../version-14.5/getting-started/options.md | 134 +++++++ .../version-14.5/getting-started/presets.md | 161 +++++++++ .../getting-started/test-environment.md | 129 +++++++ .../version-14.5/guides/absolute-imports.md | 9 + .../version-14.5/guides/angular-13+.md | 212 +++++++++++ .../version-14.5/guides/angular-ivy.md | 76 ++++ .../version-14.5/guides/esm-support.md | 73 ++++ .../version-14.5/guides/jsdom-version.md | 35 ++ .../version-14.5/guides/snapshot-testing.md | 330 ++++++++++++++++++ .../version-14.5/guides/troubleshooting.md | 286 +++++++++++++++ .../version-14.5/guides/using-with-babel.md | 56 +++ .../version-14.5/introduction.md | 17 + .../versioned_docs/version-14.5/processing.md | 6 + .../version-14.5-sidebars.json | 24 ++ website/versions.json | 1 + 18 files changed, 1734 insertions(+), 1 deletion(-) create mode 100644 website/versioned_docs/version-14.5/getting-started/installation.md create mode 100644 website/versioned_docs/version-14.5/getting-started/options.md create mode 100644 website/versioned_docs/version-14.5/getting-started/presets.md create mode 100644 website/versioned_docs/version-14.5/getting-started/test-environment.md create mode 100644 website/versioned_docs/version-14.5/guides/absolute-imports.md create mode 100644 website/versioned_docs/version-14.5/guides/angular-13+.md create mode 100644 website/versioned_docs/version-14.5/guides/angular-ivy.md create mode 100644 website/versioned_docs/version-14.5/guides/esm-support.md create mode 100644 website/versioned_docs/version-14.5/guides/jsdom-version.md create mode 100644 website/versioned_docs/version-14.5/guides/snapshot-testing.md create mode 100644 website/versioned_docs/version-14.5/guides/troubleshooting.md create mode 100644 website/versioned_docs/version-14.5/guides/using-with-babel.md create mode 100644 website/versioned_docs/version-14.5/introduction.md create mode 100644 website/versioned_docs/version-14.5/processing.md create mode 100644 website/versioned_sidebars/version-14.5-sidebars.json diff --git a/CHANGELOG.md b/CHANGELOG.md index d2d632923f..07393728af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +## [14.5.0](https://github.com/thymikee/jest-preset-angular/compare/v14.4.2...v14.5.0) (2025-01-10) + + +### Features + +* feat: add custom `jsdom` env [#2904](https://github.com/thymikee/jest-preset-angular/issues/2904) ([6045a96](https://github.com/thymikee/jest-preset-angular/commit/6045a96)), closes [#2883](https://github.com/thymikee/jest-preset-angular/issues/2883) + + +### Code Refactoring + +* refactor: add type for `serializers/index.ts` ([dd64d78](https://github.com/thymikee/jest-preset-angular/commit/dd64d78)) + + +### DEPRECATIONS + +* refactor: deprecate `defaultTransformerOptions` in `presets` ([99d3112](https://github.com/thymikee/jest-preset-angular/commit/99d3112)) +* refactor: deprecate `ngcc` util via `globalSetup` ([edeaa3f](https://github.com/thymikee/jest-preset-angular/commit/edeaa3f)) + + + ## [14.4.2](https://github.com/thymikee/jest-preset-angular/compare/v14.4.1...v14.4.2) (2024-12-03) diff --git a/package.json b/package.json index c451a59ebd..056d22b2d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jest-preset-angular", - "version": "14.4.2", + "version": "14.5.0", "description": "Jest preset configuration for Angular projects", "license": "MIT", "engines": { diff --git a/website/versioned_docs/version-14.5/getting-started/installation.md b/website/versioned_docs/version-14.5/getting-started/installation.md new file mode 100644 index 0000000000..da17233263 --- /dev/null +++ b/website/versioned_docs/version-14.5/getting-started/installation.md @@ -0,0 +1,164 @@ +--- +id: installation +title: Installation +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +### Dependencies + +You can install `jest-preset-angular` and dependencies all at once with one of the following commands. + +```bash npm2yarn +npm install -D jest jest-preset-angular @types/jest +``` + +### Configuration + +:::important + +Angular doesn't support native `async/await` in testing with `target` higher than `ES2016`, see https://github.com/angular/components/issues/21632#issuecomment-764975917 + +::: + +In your project root, create a setup file with following contents: + +```ts title="setup-jest.ts" tab={"label":"TypeScript CJS"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv(); +``` + +```ts title="setup-jest.ts" tab={"label":"TypeScript ESM"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs'; + +setupZoneTestEnv(); +``` + +Add the following section to your root Jest config + +```ts title="jest.config.ts" tab={"label":"TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label":"TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +Adjust your `tsconfig.spec.json` to be: + +```json5 title="tsconfig.spec.json" tab={"label": "Tsconfig CJS"} +{ + //... + extends: './tsconfig.json', + compilerOptions: { + //... + module: 'CommonJS', + types: ['jest'], + }, + include: ['src/**/*.spec.ts', 'src/**/*.d.ts'], + //... +} +``` + +```json title="tsconfig.spec.json" tab={"label": "Tsconfig ESM"} +{ + //... + "extends": "./tsconfig.json", + "compilerOptions": { + //... + "module": "ES2022", + "types": ["jest"] + }, + "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] + //... +} +``` + +Adjust `scripts` part your `package.json` to use `jest` instead of `ng`, e.g. + +```json title="package.json" +{ + //... + "scripts": { + "test": "jest", + "test:watch": "jest --watch" + } + //... +} +``` + +### Customizing + +#### Global mocks + +`jest-preset-angular` uses `JSDOM` which is different from normal browsers. You might need some global browser mocks to +simulate the behaviors of real browsers in `JSDOM`. To add global mocks, you can do the following: + +- Create a file `jest-global-mocks.ts` to your root project. +- Import it in your global setup file: + +```ts title="setup-jest.ts" tab={"label":"TypeScript CJS"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; +import './jest-global-mocks'; + +setupZoneTestEnv(); +``` + +```ts title="setup-jest.ts" tab={"label":"TypeScript ESM"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs'; +import './jest-global-mocks'; + +setupZoneTestEnv(); +``` + +:::tip + +An example for `jest-global-mocks.ts` + +```ts title="jest-global-mocks.ts" +Object.defineProperty(document, 'doctype', { + value: '', +}); +Object.defineProperty(window, 'getComputedStyle', { + value: () => { + return { + display: 'none', + appearance: ['-webkit-appearance'], + }; + }, +}); +/** + * ISSUE: https://github.com/angular/material2/issues/7101 + * Workaround for JSDOM missing transform property + */ +Object.defineProperty(document.body.style, 'transform', { + value: () => { + return { + enumerable: true, + configurable: true, + }; + }, +}); +``` + +::: + +#### Avoid karma conflicts + +By Angular CLI defaults you'll have a `src/test.ts` file which will be picked up by jest. To circumvent this you can either rename it to `src/karmaTest.ts` or hide it from jest by adding `/src/test.ts` to jest `testPathIgnorePatterns` option. diff --git a/website/versioned_docs/version-14.5/getting-started/options.md b/website/versioned_docs/version-14.5/getting-started/options.md new file mode 100644 index 0000000000..b63730df0f --- /dev/null +++ b/website/versioned_docs/version-14.5/getting-started/options.md @@ -0,0 +1,134 @@ +--- +id: options +title: Options +--- + +`jest-preset-angular` uses `ts-jest` options under the hood, which are located under the `transform` of Jest config object +in the `package.json` file of your project, or through a `jest.config.js`, or `jest.config.ts` file. + +More information about `ts-jest` options, see [doc](https://kulshekhar.github.io/ts-jest/docs/getting-started/options) + +:::important + +Since **v9.0.0**, `jest-preset-angular` default Jest configuration no longer provides `moduleNameMapper`. If you wish to reuse +the old `moduleNameMapper` configuration, you can put this into your Jest config. + +::: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + moduleNameMapper: { + '^src/(.*)$': '/src/$1', + '^app/(.*)$': '/src/app/$1', + '^assets/(.*)$': '/src/assets/$1', + '^environments/(.*)$': '/src/environments/$1', + }, +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + moduleNameMapper: { + '^src/(.*)$': '/src/$1', + '^app/(.*)$': '/src/app/$1', + '^assets/(.*)$': '/src/assets/$1', + '^environments/(.*)$': '/src/environments/$1', + }, +}; + +export default jestConfig; +``` + +### Processing with esbuild + +Since **v11.0.0**, `jest-preset-angular` introduced the usage of `esbuild` to process files besides TypeScript API. By default, all `.mjs` files +will be processed by `esbuild` in `jest-preset-angular`. To configure extra files to process with `esbuild`, one can do the following: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + processWithEsbuild: [] + } + ] + } +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + processWithEsbuild: [] + } + ] + } +}; + +export default jestConfig; +``` + +### Exposed configuration + +```ts title="jest.config.ts" +import type { Config } from 'jest'; + +const jestConfig: Config = { + 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', + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, +}; + +export default jestConfig; +``` + +:::important + +Jest runs with `jest-preset-angular` neither in browser nor through dev server. It uses `JSDOM` to abstract browser environment hence we depend on +`JSDOM` implementation for real browser features. + +::: + +### Brief explanation of config + +- We're using `"transform"` to pass information about configuration to use for code compilation with `ts-jest`. +- `"moduleFileExtensions"` – our modules are TypeScript (`ts`), HTML (`html`), JavaScript (`js`), JSON (`json`) and ESM JavaScript (`mjs`) files. +- `"moduleNameMapper"` – if you're using absolute imports here's how to tell Jest where to look for them; uses `RegExp`. +- `"snapshotSerializers"` - array of serializers which will be applied to snapshot the code. See more in [Snapshot testing](../guides/snapshot-testing.md) +- `"testEnvironment"` – the test environment to run on. +- `"transformIgnorePatterns"`: instruct Jest to transform any `.mjs` files which come from `node_modules`. +- `"transform"` – run every `TS`, `JS`, `MJS`, `HTML`, or `SVG` file through so called _Jest transformer_; this lets Jest understand non-JS syntax. diff --git a/website/versioned_docs/version-14.5/getting-started/presets.md b/website/versioned_docs/version-14.5/getting-started/presets.md new file mode 100644 index 0000000000..242c93b283 --- /dev/null +++ b/website/versioned_docs/version-14.5/getting-started/presets.md @@ -0,0 +1,161 @@ +--- +id: presets +title: 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` provides very opinionated presets and based on what we found to be useful. + +:::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. + +::: + +## Functions + +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: { + '^.+\\.(ts|js|mjs|html|svg)$': ['jest-preset-angular', 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 = { + ...presetConfig, +}; + +export default jestConfig; +``` + +### `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; + extensionsToTreatAsEsm: Array; + transformIgnorePatterns: Array; + transform: { + '^.+\\.(ts|js|html|svg)$': ['jest-preset-angular', 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 = { + ...presetConfig, +}; + +export default jestConfig; +``` + +### Legacy presets + +:::warning + +`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'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular/presets/defaults-esm', +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/getting-started/test-environment.md b/website/versioned_docs/version-14.5/getting-started/test-environment.md new file mode 100644 index 0000000000..538fdc6983 --- /dev/null +++ b/website/versioned_docs/version-14.5/getting-started/test-environment.md @@ -0,0 +1,129 @@ +--- +id: test-environment +title: Test environment +--- + +In Jest, a test environment defines the sandbox context in which your tests run. +For Angular projects, setting up the correct test environment is essential to ensure compatibility with the +framework-specific features, such as dependency injection and change detection. + +`jest-preset-angular` provides utility functions to simplify setting up a Jest test environment tailored for Angular projects. +These functions support both **zone-based** and **zoneless** environments, catering to different testing needs. + +## Functions + +import TOCInline from '@theme/TOCInline'; + + + +--- + +### `setupZoneTestEnv(options)` + +Configures a test environment that uses `zone.js`, which is the mechanism for tracking asynchronous operations. +It is suitable for most Angular applications that rely on `zone.js` for change detection and other framework features. + +You can customize the environment by providing options as function arguments. + +#### Parameters + +- `options`**(optional)**: An object follows [TestEnvironmentOptions interface](https://github.com/angular/angular/blob/a55341b1ab8d2bc4285a4cce59df7fc0b23c0125/packages/core/testing/src/test_bed_common.ts#L95), which allows fine-tuning the environment. + +#### Example: + +- Create a Jest setup file: + +```ts title="setup-jest.ts" tab={"label": "TypeScript CJS"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + //...options +}); +``` + +```ts title="setup-jest.ts" tab={"label": "TypeScript ESM"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs'; + +setupZoneTestEnv({ + //...options +}); +``` + +- Update your Jest configuration: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +### `setupZonelessTestEnv(options)` + +Configures a test environment that **DOESN'T** use `zone.js`, as described in [Angular experimental zoneless guide](https://angular.dev/guide/experimental/zoneless). +It is designed for projects that have disabled `zone.js`, which can lead to improved performance and simplified testing. + +You can customize the environment by providing options as function arguments. + +#### Parameters + +- `options`**(optional)**: An object follows [TestEnvironmentOptions interface](https://github.com/angular/angular/blob/a55341b1ab8d2bc4285a4cce59df7fc0b23c0125/packages/core/testing/src/test_bed_common.ts#L95), which allows fine-tuning the environment. + +#### Example: + +- Create a Jest setup file: + +```ts title="setup-jest.ts" tab={"label": "TypeScript CJS"} +import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless'; + +setupZonelessTestEnv({ + //...options +}); +``` + +```ts title="setup-jest.ts" tab={"label": "TypeScript ESM"} +import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless/index.mjs'; + +setupZonelessTestEnv({ + //...options +}); +``` + +- Update your Jest configuration: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/guides/absolute-imports.md b/website/versioned_docs/version-14.5/guides/absolute-imports.md new file mode 100644 index 0000000000..e679d83e3b --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/absolute-imports.md @@ -0,0 +1,9 @@ +--- +id: absolute-imports +title: Absolute Imports +--- + +If you wish to use TypeScript path mappings which are defined in `paths` of your tsconfig, make sure that you create the +similar mapping for `moduleNameMapper` in Jest config. + +More information see `ts-jest` [paths mapping](https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping) configuration documentation diff --git a/website/versioned_docs/version-14.5/guides/angular-13+.md b/website/versioned_docs/version-14.5/guides/angular-13+.md new file mode 100644 index 0000000000..6b346a9a4e --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/angular-13+.md @@ -0,0 +1,212 @@ +--- +id: angular-13+ +title: Angular >=13 +--- + +**Angular 13** introduces ESM package format for Angular packages. `jest-preset-angular` +currently supports testing with Jest in `CommonJS` mode with **Angular 13** using [default preset](../getting-started/presets.md). + +:::important + +With Jest 28 and `jest-preset-angular` **v12.0.0**, `ng-jest-resolver` is no longer required to have in Jest config. This +resolver is also excluded from our default and default ESM presets. + +::: + +Starting from **v11.0.0**, `jest-preset-angular` introduces a few extra changes to be able to run Jest with **Angular 13**: + +- `moduleFileExtensions` is updated to include `mjs` files as accepted module format. + +- `transformIgnorePatterns` is added to inform Jest to transform `.mjs` files. + +- `transform` is updated to include `.mjs` extension to transform to `CommonJS` codes. + +## Migration steps from Angular < 13 + +- Upgrade the project to **Angular 13** following [guide](https://angular.dev/update-guide/) + +- If one is using the default preset as following: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + preset: 'jest-preset-angular', +}; + +export default jestConfig; +``` + +there are no migration steps required + +### Using ES Modules + +ES Modules support is new and may encounter issues. See [example-apps](https://github.com/thymikee/jest-preset-angular/tree/main/examples) for the tests that run using ESM mode. + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; +import { pathsToModuleNameMapper } from 'ts-jest'; +import { compilerOptions } from './tsconfig.json'; + +const jestConfig: Config = { + preset: 'jest-preset-angular/presets/defaults-esm', + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig-esm.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + isolatedModules: true, + useESM: true, + }, + ], + }, + moduleNameMapper: { + ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '' }), + tslib: 'tslib/tslib.es6.js', + }, + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; +import { pathsToModuleNameMapper } from 'ts-jest'; +import { compilerOptions } from './tsconfig.json'; + +const jestConfig: Config = { + preset: 'jest-preset-angular/presets/defaults-esm', + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig-esm.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + isolatedModules: true, + useESM: true, + }, + ], + }, + moduleNameMapper: { + ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '' }), + tslib: 'tslib/tslib.es6.js', + }, + setupFilesAfterEnv: ['/setup-jest.ts'], +}; + +export default jestConfig; +``` + +Before upgrading to ng13 and switching to ES Modules, your `setup-jest.ts` file most likely uses the preset `setup-jest`, like the following: + +```ts title="setup-jest.ts" tab={"label":"TypeScript CJS"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv(); +``` + +```ts title="setup-jest.ts" tab={"label":"TypeScript ESM"} +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs'; + +setupZoneTestEnv(); +``` + +## Potential issues with Angular 13 ESM package format and workaround + +### `Cannot find modules` error when importing any deep paths from Angular ESM format packages + +``` +Cannot find module '@angular/common/locales/xx' from 'src/app/app.component.spec.ts' +``` + +To fix this issue, one needs to add `mjs` to `moduleFileExtensions` as following + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'], +}; + +export default jestConfig; +``` + +### Usage with Angular libraries which are built with Angular CLI 13 + +Besides, the changes in Angular packages themselves, **Angular** libraries which are built with **Angular CLI 13** also introduce +ESM package format. Similar to Angular packages, Jest doesn't understand `.mjs` files which are in these new format +libraries in Jest **CommonJS** mode. + +To fix this issue, one should modify `transformIgnorePatterns` to be as following: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], +}; + +export default jestConfig; +``` + +### Usage with Ionic 6 or 7 + +To support Ionic 6 or 7 you will need to modify `transformIgnorePatterns` to be as following: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['/node_modules/(?!(@ionic/core|@ionic/angular|@stencil/core|.*\\.mjs$))'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['/node_modules/(?!(@ionic/core|@ionic/angular|@stencil/core|.*\\.mjs$))'], +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/guides/angular-ivy.md b/website/versioned_docs/version-14.5/guides/angular-ivy.md new file mode 100644 index 0000000000..aa9e721283 --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/angular-ivy.md @@ -0,0 +1,76 @@ +--- +id: angular-ivy +title: Angular Ivy +--- + +:::warning + +This guide is now **DEPRECATED** and will be removed in the next major release together with the below APIs. + +::: + +Starting from **v9.0.0+**, `jest-preset-angular` is fully compatible with Angular Ivy. To make sure that Jest uses the +Angular Ivy, you must run `ngcc` before running tests. `ngcc` will transform all Angular-format packages to be compatible +with Ivy compiler. + +`jest-preset-angular` also provides a Jest global setup file to help you to run `ngcc` with Jest. Add to the following section: + +- to your root Jest config + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + globalSetup: 'jest-preset-angular/global-setup', +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + globalSetup: 'jest-preset-angular/global-setup', +}; + +export default jestConfig; +``` + +## Control ngcc processing + +Since **v12.0.0**, `jest-preset-angular` provide a possibility to skip `ngcc` via `globalThis` by doing the following + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +globalThis.ngJest = { + skipNgcc: true, + tsconfig: 'tsconfig.spec.json', // this is the project root tsconfig +}; + +const jestConfig: Config = { + //... + globalSetup: 'jest-preset-angular/global-setup', +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +globalThis.ngJest = { + skipNgcc: true, + tsconfig: 'tsconfig.spec.json', // this is the project root tsconfig +}; + +const jestConfig: Config = { + //... + globalSetup: 'jest-preset-angular/global-setup', +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/guides/esm-support.md b/website/versioned_docs/version-14.5/guides/esm-support.md new file mode 100644 index 0000000000..e1dad084d4 --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/esm-support.md @@ -0,0 +1,73 @@ +--- +id: esm-support +title: ESM Support +--- + +To use `jest-preset-angular` with ESM support, you'll first need to check [ESM Jest documentation](https://jestjs.io/docs/en/ecmascript-modules). + +`jest-preset-angular` supports ESM via a `ts-jest` config option [useESM](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/useESM) in combination with jest config option [extensionsToTreatAsEsm](https://jestjs.io/docs/en/configuration#extensionstotreatasesm-arraystring). + +There is also a [preset](../getting-started/presets.md) to work with ESM. + +:::tip + +We have [example apps](https://github.com/thymikee/jest-preset-angular/tree/main/examples) which contains base ESM setup to work with Jest and Angular. + +::: + +Besides, there is utility function to ensure that Jest can set up test environment properly. + +```ts title="setup-jest.ts" +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs'; + +setupZoneTestEnv(); +``` + +### Examples + +#### Manual configuration + +```ts title="jest.config.mts" +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + extensionsToTreatAsEsm: ['.ts'], + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + useESM: true, + }, + ], + }, +}; + +export default jestConfig; +``` + +#### Use ESM presets + +:::tip + +Jest will attempt to load **ESM** files from `node_modules` with default `jest-resolve` which usually works for most of the cases. +However, there are cases like Angular libraries **ESM** built files or **ESM** files which are outside `node_modules` might not be loaded +correctly. + +To fix that, one can use `moduleNameMapper` in jest config to instruct Jest to load the correct **ESM** files or create a +custom Jest [resolver](https://jestjs.io/docs/configuration#resolver-string). + +::: + +```ts title="jest.config.mts" +import type { Config } from 'jest'; + +const jestConfig = { + //... + preset: 'jest-preset-angular/presets/defaults-esm', +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/guides/jsdom-version.md b/website/versioned_docs/version-14.5/guides/jsdom-version.md new file mode 100644 index 0000000000..bed0fd3ce6 --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/jsdom-version.md @@ -0,0 +1,35 @@ +--- +id: jsdom-version +title: JSDOM version +--- + +`jest-preset-angular` provides a way to configure a different version of `JSDOM` than the one ships with `Jest` +via a custom `JSDOM` environment. One can follow the below steps to configure a different JSDOM version: + +- Install the desired JSDOM version + +```bash npm2yarn +npm install -D jsdom@ +``` + +- In Jest config, set the `testEnvironment` like following + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + testEnvironment: 'jest-preset-angular/environments/jsdom', +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + testEnvironment: 'jest-preset-angular/environments/jsdom', +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/guides/snapshot-testing.md b/website/versioned_docs/version-14.5/guides/snapshot-testing.md new file mode 100644 index 0000000000..6ec271d327 --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/snapshot-testing.md @@ -0,0 +1,330 @@ +--- +id: snapshot-testing +title: Snapshot testing +--- + +`jest-preset-angular` provides several snapshot serializers to generate clearer and more human-readable snapshot. + +:::info + +**BY DEFAULT**, the [preset](../getting-started/presets.md) provides all of the snapshot serializers below. + +::: + +## Snapshot serializers + +import TOCInline from '@theme/TOCInline'; + + + +--- + +### Remove html comments (`html-comment`) + +Allow removing all the comments in the component HTML in snapshot. + +#### Examples: + +- In Jest config file + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/html-comment'], + //[...] +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/html-comment'], + //[...] +}; + +export default jestConfig; +``` + +- Or in setup test environment file + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="setup-jest.ts" +import removeHtmlCommentsSerializer from 'jest-preset-angular/build/serializers/html-comment'; + +expect.addSnapshotSerializer(removeHtmlCommentsSerializer); +``` + +- Or in individual test files + +```ts title="foo.component.spec.ts" +import removeHtmlCommentsSerializer from 'jest-preset-angular/build/serializers/html-comment'; + +expect.addSnapshotSerializer(removeHtmlCommentsSerializer); + +it('should work', () => { + //[...] +}); +``` + +### Display component HTML (`ng-snapshot`) + +Allow displaying component HTML with data in snapshot. + +#### Parameters + +- options(**optional**): + - omitAllCompAttrs: remove all component DOM attributes + +```ts +type NgSnapshotOptions = { + omitAllCompAttrs?: boolean; +}; +``` + +#### Examples: + +- In Jest config + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/ng-snapshot'], + //[...] +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/ng-snapshot'], + //[...] +}; + +export default jestConfig; +``` + +- Or in setup test environment file + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="setup-jest.ts" +import componentSnapshotSerializer from 'jest-preset-angular/build/serializers/ng-snapshot'; + +expect.addSnapshotSerializer(componentSnapshotSerializer); +``` + +- Or in individual test files + +```ts title="foo.component.spec.ts" +import componentSnapshotSerializer from 'jest-preset-angular/build/serializers/ng-snapshot'; + +expect.addSnapshotSerializer(componentSnapshotSerializer); + +it('should work', () => { + //[...] +}); +``` + +#### With options + +:::info Effective priority + +The configured serializers will have affect in this order: + +`Jest config` -> `setup files` -> `test files` + +The later the higher priority. This means that with the same serializer, the later one will override the configuration +of the previous one in the chain. + +::: + +- In setup files: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; + +export default jestConfig; +``` + +```ts title="setup-jest.ts" +import componentSnapshotSerializer from 'jest-preset-angular/build/serializers/ng-snapshot'; + +expect.addSnapshotSerializer({ + print: (val, print, indent, options, colors) => + componentSnapshotSerializer.print( + val, + print, + indent, + { + ...options, + omitAllCompAttrs: true, + }, + colors, + ), + test: componentSnapshotSerializer.test, +}); +``` + +- or in individual test files: + +```ts title="foo.component.spec.ts" +import componentSnapshotSerializer from 'jest-preset-angular/build/serializers/ng-snapshot'; + +expect.addSnapshotSerializer({ + print: (val, print, indent, options, colors) => + componentSnapshotSerializer.print( + val, + print, + indent, + { + ...options, + omitAllCompAttrs: true, + }, + colors, + ), + test: componentSnapshotSerializer.test, +}); + +it('should work', () => { + //[...] +}); +``` + +### Remove Angular attributes (`no-ng-attributes`) + +Allow removing attributes generated by Angular fixture, like `ng-reflect-*`, `ng-version="*"`, `_ngcontent-c*` etc., from component snapshot + +#### Examples: + +- In Jest config + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/no-ng-attributes'], + //[...] +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + snapshotSerializers: ['jest-preset-angular/build/serializers/no-ng-attributes'], + //[...] +}; + +export default jestConfig; +``` + +- Or in setup test environment file + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //[...] + setupFilesAfterEnv: ['./setup-jest.ts'], + //[...] +}; +``` + +```ts title="setup-jest.ts" +import removeNgAttributes from 'jest-preset-angular/build/serializers/no-ng-attributes'; + +expect.addSnapshotSerializer(removeNgAttributes); +``` + +- Or in individual test files + +```ts title="foo.component.spec.ts" +import removeNgAttributes from 'jest-preset-angular/build/serializers/no-ng-attributes'; + +expect.addSnapshotSerializer(removeNgAttributes); + +it('should work', () => { + //[...] +}); +``` diff --git a/website/versioned_docs/version-14.5/guides/troubleshooting.md b/website/versioned_docs/version-14.5/guides/troubleshooting.md new file mode 100644 index 0000000000..6b1389abb2 --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/troubleshooting.md @@ -0,0 +1,286 @@ +--- +id: troubleshooting +title: Troubleshooting +--- + +You can check Jest [troubleshooting guide](https://jestjs.io/docs/en/troubleshooting) + +## Common issues + +Problems may arise if you're using custom builds (this preset is tailored for `angular-cli` as firstly priority). Please be advised that every entry in default configuration may be overridden to best suite your app's needs. + +### Can't resolve all parameters for SomeClass(?) + +With Angular 8 and higher, a [change to the way the Angular CLI works](https://github.com/thymikee/jest-preset-angular/issues/288) may be causing your metadata to be lost. You can update your `tsconfig.spec.json` to include the `emitDecoratorMetadata` compiler option: + +```json title="tsconfig.spec.json" +{ + "compilerOptions": { + "emitDecoratorMetadata": true + } +} +``` + +In general, this is related to `Angular`'s reflection and also depends on a reflection library, as e. g. included in `core-js`. We use our own minimal reflection that satisfy `Angular`'s current requirements, but in case these change, you can install `core-js` and import the reflection library in your `setup-jest.ts`: + +```ts title="setup-jest.ts" +import 'core-js/es/reflect'; +import 'core-js/proposals/reflect-metadata'; +``` + +Note that this might also be related to other issues with the dependency injection and parameter type reflection. + +### @Input() bindings are not reflected into fixture when `ChangeDetectionStrategy.OnPush` is used + +This issue is not related to Jest, [it's a known Angular bug](https://github.com/angular/angular/issues/12313) + +To mitigate this, you need to wrap your component under test, into some container component with default change detection strategy (`ChangeDetectionStrategy.Default`) and pass props through it, or overwrite change detection strategy within `TestBed` setup, if it's not critical for the test. + +```ts title="some.component.spec.ts" +beforeEach(async(() => { + TestBed.configureTestingModule({ declarations: [PizzaItemComponent] }) + .overrideComponent(PizzaItemComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default }, + }) + .compileComponents(); +})); +``` + +### The animation trigger "transformMenu" has failed + +The currently used JSDOM version handles this, but older versions used before v7 of this preset was missing transform property. To patch it for Angular Material, use this workaround. + +Add this to your global mock file + +```ts title="jest-global-mocks.ts" +Object.defineProperty(document.body.style, 'transform', { + value: () => { + return { + enumerable: true, + configurable: true, + }; + }, +}); +``` + +Reference: https://github.com/angular/material2/issues/7101 + +### Unexpected token [import|export|other] + +This means, that a file is not transformed through `TypeScript` compiler, e.g. because it is a `JS` file with `TS` syntax, or +it is published to npm as uncompiled source files. Here's what you can do. A typical Jest error is like this: + +```shell +({"Object.":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '@angular/core'; + ^^^^^^ + SyntaxError: Cannot use import statement outside a module +``` + +To fix the issue, one needs to adjust `transformIgnorePatterns` whitelist: + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['node_modules/(?!@angular|@ngrx)'], +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + // ...other options + transformIgnorePatterns: ['node_modules/(?!@angular|@ngrx)'], +}; + +export default jestConfig; +``` + +By default, Jest doesn't transform `node_modules`, because they should be valid JavaScript files. However, it happens that +library authors assume that you'll compile their sources. So you have to tell this to Jest explicitly. +Above snippet means that `@angular`, `@ngrx` will be transformed, even though they're `node_modules`. + +If the dependency causing the issue is a sub dependency of a `node_modules` packages or a module designed to be used with nodeJS, a custom resolver could be required to fix the issue. [See below](#resolver-needed-for-some-javascript-library-or-nested-dependencies) for more information. + +### Allow vendor libraries like jQuery, etc... + +The same like normal Jest configuration, you can load jQuery in your Jest setup file. For example your Jest setup file is `setup-jest.ts` you can declare jQuery: + +```ts title="setup-jest.ts" +window.$ = require('path/to/jquery'); +``` + +or + +```ts title="setup-jest.ts" +import $ from 'jquery'; +global.$ = global.jQuery = $; +``` + +The same declaration can be applied to other vendor libraries. + +Reference: https://github.com/facebook/jest/issues/708 + +### Coverage fail but tests pass + +This issue happens because Jest uses `Babel` behind the screen to create coverage reporter. To fix this issue, one can do the following: + +- Install `babel-jest`, `@babel/core` and `@babel/preset-env` +- Create a `.babelrc` at the same place where Jest config file locates and define the necessary `Babel` plugins. + For example + +```json title=".babelrc" +{ + // this plugin will fix issue with class inheritance + "plugins": ["@babel/plugin-transform-classes"] +} +``` + +- Define the usage of `Babel` in Jest config via `ts-jest` option, for example + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + //... + babelConfig: true, + //... + }, + ], + }, +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + transform: { + '^.+\\.(ts|js|mjs|html|svg)$': [ + 'jest-preset-angular', + { + //... + babelConfig: true, + //... + }, + ], + }, +}; + +export default jestConfig; +``` + +### Resolver needed for some javascript library or nested dependencies + +This can happen in two identified cases. + +#### Javascript library + +When using a javascript SDK/Library in Angular, some javascript methods could fail to be properly rendered in tests. Some examples are the `firebase` and `firebase/compat` SDK. + +A typical error could appear as: + +```shell +TypeError: Cannot read properties of undefined (reading 'FacebookAuthProvider') + import firebase from 'firebase/compat/app'; + + > export const facebookAuthProvider = new firebase.auth.FacebookAuthProvider(); +``` + +#### Nested dependency (`node_modules` package within another package `node_nodules`) + +Some nested dependency tree could trigger some errors while running the tests because some bundles (especially ESM ones) could be somehow errored. An example is the `@angular/fire` package which uses the `@firebase/firestore` package. + +A typical error could appear as: + +```shell +node_modules\@angular\fire\node_modules\@firebase\firestore\dist\index.esm2017.js:12705 + function (t, e) { + ^^^^^^^^ + + SyntaxError: Function statements require a function name +``` + +#### Resolution + +In these cases, a `transformIgnorePatterns` whitelisting could not fix the issue. The solution here is to use a custom `resolver`. You may or may not need to remove entries from `transformIgnorePatterns` whitelisting. + +Here is an example of a resolver which would fix `firebase` related packages. + +```ts title="jest.resolver.ts" +import type { SyncResolver } from 'jest-resolve'; + +const myResolver: SyncResolver = (path, options) => { + // Call the defaultResolver, so we leverage its cache, error handling, etc. + return options.defaultResolver(path, { + ...options, + // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) + packageFilter: (pkg) => { + const pkgNamesToTarget = new Set([ + 'rxjs', + '@firebase/auth', + '@firebase/storage', + '@firebase/functions', + '@firebase/database', + '@firebase/auth-compat', + '@firebase/database-compat', + '@firebase/app-compat', + '@firebase/firestore', + '@firebase/firestore-compat', + '@firebase/messaging', + '@firebase/util', + 'firebase', + ]); + + if (pkgNamesToTarget.has(pkg.name)) { + // console.log('>>>', pkg.name) + delete pkg['exports']; + delete pkg['module']; + } + + return pkg; + }, + }); +}; + +export = myResolver; +``` + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + resolver: '/src/jest.resolver.ts', + //... +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + resolver: '/src/jest.resolver.js', + //... +}; + +export default jestConfig; +``` + +### Inject dependencies with TypeScript interface or exported namespace + +Please use Angular [inject](https://angular.dev/api/core/inject) instead of [@Inject](https://angular.dev/api/core/Inject). +This is because `jest-preset-angular` has caveat when working with class constructor and decorator. diff --git a/website/versioned_docs/version-14.5/guides/using-with-babel.md b/website/versioned_docs/version-14.5/guides/using-with-babel.md new file mode 100644 index 0000000000..d3c7888f5c --- /dev/null +++ b/website/versioned_docs/version-14.5/guides/using-with-babel.md @@ -0,0 +1,56 @@ +--- +id: using-with-babel +title: Using with Babel +--- + +If you wish to use `Babel`, you need to say jest to transpile such files manually. + +1. Install dependencies required by the official Jest documentation for [Babel integration](https://jest-bot.github.io/jest/docs/babel.html). + +2. Install `@babel/preset-env` and add `babel.config.js` (or modify existing if needed) with the following content: + +```js title="babel.config.js" +module.exports = function (api) { + api.cache(true); + + const presets = ['@babel/preset-env']; + const plugins = []; + + return { + presets, + plugins, + }; +}; +``` + +_Note: do not use a `.babelrc` file otherwise the packages that you specify in the next step will not be picked up. CF [Babel documentation](https://babeljs.io/docs/en/configuration#what-s-your-use-case) and the comment `You want to compile node_modules? babel.config.js is for you!`_. + +3. Update Jest configuration (by default TypeScript process untranspiled JS files which is source of the problem): + +```ts title="jest.config.ts" tab={"label": "TypeScript CJS"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + transform: { + '^.+\\.(ts|html)$': 'jest-preset-angular', + '^.+\\.js$': 'babel-jest', + }, +}; + +export default jestConfig; +``` + +```ts title="jest.config.mts" tab={"label": "TypeScript ESM"} +import type { Config } from 'jest'; + +const jestConfig: Config = { + //... + transform: { + '^.+\\.(ts|html)$': 'jest-preset-angular', + '^.+\\.js$': 'babel-jest', + }, +}; + +export default jestConfig; +``` diff --git a/website/versioned_docs/version-14.5/introduction.md b/website/versioned_docs/version-14.5/introduction.md new file mode 100644 index 0000000000..01d52b7a75 --- /dev/null +++ b/website/versioned_docs/version-14.5/introduction.md @@ -0,0 +1,17 @@ +--- +id: introduction +title: Introduction +description: Jest preset configuration for Angular projects. +slug: / +--- + +`jest-preset-angular` is Jest preset configuration and TypeScript preprocessor with source map support for Jest that lets you use Jest to test Angular projects. + +This is a part of the article: [Testing Angular faster with Jest](https://www.xfive.co/blog/testing-angular-faster-jest/). + +:::important + +Starting from **v9.0.0**, we follow closely native `Karma + Jasmine` implementation which is default provided by +`@angular/cli`. This will make the testing experience with Jest more inline native with Angular testing experience. + +::: diff --git a/website/versioned_docs/version-14.5/processing.md b/website/versioned_docs/version-14.5/processing.md new file mode 100644 index 0000000000..77b8f5a295 --- /dev/null +++ b/website/versioned_docs/version-14.5/processing.md @@ -0,0 +1,6 @@ +--- +id: processing +title: Processing flow +--- + +`jest-preset-angular` follows the processing flow of `ts-jest`, see more at https://kulshekhar.github.io/ts-jest/docs/processing diff --git a/website/versioned_sidebars/version-14.5-sidebars.json b/website/versioned_sidebars/version-14.5-sidebars.json new file mode 100644 index 0000000000..9fa6c495d2 --- /dev/null +++ b/website/versioned_sidebars/version-14.5-sidebars.json @@ -0,0 +1,24 @@ +{ + "docs": { + "jest-preset-angular": [ + "introduction", + "processing" + ], + "Getting Started": [ + "getting-started/installation", + "getting-started/presets", + "getting-started/options", + "getting-started/test-environment" + ], + "Guides": [ + "guides/angular-ivy", + "guides/angular-13+", + "guides/esm-support", + "guides/jsdom-version", + "guides/snapshot-testing", + "guides/using-with-babel", + "guides/absolute-imports", + "guides/troubleshooting" + ] + } +} diff --git a/website/versions.json b/website/versions.json index cd80d4e32d..ab7f49af24 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,5 @@ [ + "14.5", "14.4", "14.3", "14.2",