diff --git a/CHANGELOG.md b/CHANGELOG.md index cf47e4302d60..93d9585e8bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - `[jest-circus]` Fix snapshot matchers in concurrent tests when nr of tests exceeds `maxConcurrency` ([#14335](https://github.com/jestjs/jest/pull/14335)) - `[jest-snapshot]` Move `@types/prettier` from `dependencies` to `devDependencies` ([#14328](https://github.com/jestjs/jest/pull/14328)) +- `[jest-snapshot]` Throw an explicit error if Prettier v3 is used ([#14367](https://github.com/jestjs/jest/pull/14367)) - `[jest-reporters]` Add "skipped" and "todo" symbols to Github Actions Reporter ([#14309](https://github.com/jestjs/jest/pull/14309)) ### Chore & Maintenance diff --git a/docs/Configuration.md b/docs/Configuration.md index b9ac0d926541..f60f505bef71 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1144,6 +1144,41 @@ Default: `'prettier'` Sets the path to the [`prettier`](https://prettier.io/) node module used to update inline snapshots. +
+Prettier version 3 is not supported! + +You can either pass `prettierPath: null` in your config to disable using prettier if you don't need it, or use v2 of Prettier solely for Jest. + +```json title="package.json" +{ + "devDependencies": { + "prettier-2": "npm:prettier@^2" + } +} +``` + +```js tab +/** @type {import('jest').Config} */ +const config = { + prettierPath: require.resolve('prettier-2'), +}; + +module.exports = config; +``` + +```ts tab +import type {Config} from 'jest'; + +const config: Config = { + prettierPath: require.resolve('prettier-2'), +}; + +export default config; +``` + +We hope to support Prettier v3 seamlessly out of the box in a future version of Jest. See [this](https://github.com/jestjs/jest/issues/14305) tracking issue. +
+ ### `projects` \[array<string | ProjectConfig>] Default: `undefined` diff --git a/e2e/__tests__/toMatchInlineSnapshotWithPretttier3.test.ts b/e2e/__tests__/toMatchInlineSnapshotWithPretttier3.test.ts new file mode 100644 index 000000000000..2cc01798b60e --- /dev/null +++ b/e2e/__tests__/toMatchInlineSnapshotWithPretttier3.test.ts @@ -0,0 +1,85 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as path from 'path'; +import {cleanup, runYarnInstall, writeFiles} from '../Utils'; +import runJest from '../runJest'; + +const DIR = path.resolve( + __dirname, + '../to-match-inline-snapshot-with-prettier-3', +); +const TESTS_DIR = path.resolve(DIR, '__tests__'); +const JEST_CONFIG_PATH = path.resolve(DIR, 'jest.config.js'); + +beforeAll(() => { + runYarnInstall(DIR); +}); +beforeEach(() => { + cleanup(TESTS_DIR); + cleanup(JEST_CONFIG_PATH); +}); +afterAll(() => { + cleanup(TESTS_DIR); + cleanup(JEST_CONFIG_PATH); +}); + +test('throws correct error', () => { + writeFiles(DIR, { + 'jest.config.js': ` + module.exports = {prettierPath: require.resolve('prettier')}; + `, + }); + writeFiles(TESTS_DIR, { + 'test.js': ` + test('snapshots', () => { + expect(3).toMatchInlineSnapshot(); + }); + `, + }); + const {stderr, exitCode} = runJest(DIR, ['--ci=false']); + expect(stderr).toContain( + 'Jest: Inline Snapshots are not supported when using Prettier 3.0.0 or above.', + ); + expect(exitCode).toBe(1); +}); + +test('supports passing `null` as `prettierPath`', () => { + writeFiles(DIR, { + 'jest.config.js': ` + module.exports = {prettierPath: null}; + `, + }); + writeFiles(TESTS_DIR, { + 'test.js': ` + test('snapshots', () => { + expect(3).toMatchInlineSnapshot(); + }); + `, + }); + const {stderr, exitCode} = runJest(DIR, ['--ci=false']); + expect(stderr).toContain('Snapshots: 1 written, 1 total'); + expect(exitCode).toBe(0); +}); + +test('supports passing `prettier-2` as `prettierPath`', () => { + writeFiles(DIR, { + 'jest.config.js': ` + module.exports = {prettierPath: require.resolve('prettier-2')}; + `, + }); + writeFiles(TESTS_DIR, { + 'test.js': ` + test('snapshots', () => { + expect(3).toMatchInlineSnapshot(); + }); + `, + }); + const {stderr, exitCode} = runJest(DIR, ['--ci=false']); + expect(stderr).toContain('Snapshots: 1 written, 1 total'); + expect(exitCode).toBe(0); +}); diff --git a/e2e/to-match-inline-snapshot-with-prettier-3/package.json b/e2e/to-match-inline-snapshot-with-prettier-3/package.json new file mode 100644 index 000000000000..19cd4056a1bd --- /dev/null +++ b/e2e/to-match-inline-snapshot-with-prettier-3/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "prettier": "^3.0.0", + "prettier-2": "npm:prettier@^2" + } +} diff --git a/e2e/to-match-inline-snapshot-with-prettier-3/yarn.lock b/e2e/to-match-inline-snapshot-with-prettier-3/yarn.lock new file mode 100644 index 000000000000..23cdfba11cd9 --- /dev/null +++ b/e2e/to-match-inline-snapshot-with-prettier-3/yarn.lock @@ -0,0 +1,33 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"prettier-2@npm:prettier@^2": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" + bin: + prettier: bin-prettier.js + checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 + languageName: node + linkType: hard + +"prettier@npm:^3.0.0": + version: 3.0.0 + resolution: "prettier@npm:3.0.0" + bin: + prettier: bin/prettier.cjs + checksum: 6a832876a1552dc58330d2467874e5a0b46b9ccbfc5d3531eb69d15684743e7f83dc9fbd202db6270446deba9c82b79d24383d09924c462b457136a759425e33 + languageName: node + linkType: hard + +"root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + dependencies: + prettier: ^3.0.0 + prettier-2: "npm:prettier@^2" + languageName: unknown + linkType: soft diff --git a/packages/jest-snapshot/src/InlineSnapshots.ts b/packages/jest-snapshot/src/InlineSnapshots.ts index 0f7fdb870874..2864a8c8bce6 100644 --- a/packages/jest-snapshot/src/InlineSnapshots.ts +++ b/packages/jest-snapshot/src/InlineSnapshots.ts @@ -6,6 +6,7 @@ */ import * as path from 'path'; +import {types} from 'util'; import type {ParseResult, PluginItem} from '@babel/core'; import type { Expression, @@ -60,8 +61,20 @@ export function saveInlineSnapshots( try { // @ts-expect-error requireOutside Babel transform prettier = requireOutside(prettierPath) as Prettier; - } catch { - // Continue even if prettier is not installed. + + if (semver.gte(prettier.version, '3.0.0')) { + throw new Error( + 'Jest: Inline Snapshots are not supported when using Prettier 3.0.0 or above.\nSee https://jestjs.io/docs/configuration/#prettierpath-string for alternatives.', + ); + } + } catch (error) { + if (!types.isNativeError(error)) { + throw error; + } + + if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') { + throw error; + } } }