diff --git a/CHANGELOG.md b/CHANGELOG.md
index cabe3e1e4403..830993a75ed1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
- `[@jest/expect-utils]` Fix deep equality of ImmutableJS Record ([#13055](https://github.com/facebook/jest/pull/13055))
- `[jest-haste-map]` Increase the maximum possible file size that jest-haste-map can handle ([#13094](https://github.com/facebook/jest/pull/13094))
- `[jest-snapshot]` Make `prettierPath` optional in `SnapshotState` ([#13149](https://github.com/facebook/jest/pull/13149))
+- `[jest-snapshot]` Fix parsing error from inline snapshot files with `JSX` ([#12760](https://github.com/facebook/jest/pull/12760))
- `[jest-worker]` When a process runs out of memory worker exits correctly and doesn't spin indefinitely ([#13054](https://github.com/facebook/jest/pull/13054))
### Chore & Maintenance
diff --git a/e2e/__tests__/toMatchInlineSnapshotWithJSX.test.ts b/e2e/__tests__/toMatchInlineSnapshotWithJSX.test.ts
index ef1b98b5c35c..1f5b63fa0a0e 100644
--- a/e2e/__tests__/toMatchInlineSnapshotWithJSX.test.ts
+++ b/e2e/__tests__/toMatchInlineSnapshotWithJSX.test.ts
@@ -109,3 +109,52 @@ it('successfully runs the tests with external babel config', () => {
expect(updateSnapshotRun.exitCode).toBe(0);
expect(updateSnapshotRun.stderr).toContain('1 snapshot updated.');
});
+
+it('successfully runs the tests with inline babel config', () => {
+ writeFiles(DIR, {
+ 'package.json': JSON.stringify({
+ ...pkg,
+ jest: {
+ testEnvironment: 'jsdom',
+ transform: {
+ '^.+\\.(js|jsx)$': ['babel-jest', babelConfig],
+ },
+ },
+ }),
+ });
+
+ const normalRun = runWithJson(DIR, []);
+ expect(normalRun.exitCode).toBe(1);
+ expect(normalRun.stderr).toContain('1 snapshot failed from 1 test suite.');
+ expect(normalRun.json.testResults[0].message).toMatchInlineSnapshot(`
+ " ●
x
+
+ expect(received).toMatchInlineSnapshot(snapshot)
+
+ Snapshot name: \`x
1\`
+
+ - Snapshot - 1
+ + Received + 1
+
+
+ - y
+ + x
+
+
+ 3 |
+ 4 | test('x
', () => {
+ > 5 | expect(renderer.create(x
).toJSON()).toMatchInlineSnapshot(\`
+ | ^
+ 6 |
+ 7 | y
+ 8 |
+
+ at Object.toMatchInlineSnapshot (__tests__/MismatchingSnapshot.test.js:5:50)
+ "
+ `);
+
+ const updateSnapshotRun = runJest(DIR, ['--updateSnapshot']);
+
+ expect(updateSnapshotRun.exitCode).toBe(0);
+ expect(updateSnapshotRun.stderr).toContain('1 snapshot updated.');
+});
diff --git a/packages/jest-snapshot/package.json b/packages/jest-snapshot/package.json
index 725514e6bbdf..18feba9e57cb 100644
--- a/packages/jest-snapshot/package.json
+++ b/packages/jest-snapshot/package.json
@@ -19,6 +19,7 @@
"dependencies": {
"@babel/core": "^7.11.6",
"@babel/generator": "^7.7.2",
+ "@babel/plugin-syntax-jsx": "^7.7.2",
"@babel/plugin-syntax-typescript": "^7.7.2",
"@babel/traverse": "^7.7.2",
"@babel/types": "^7.3.3",
diff --git a/packages/jest-snapshot/src/InlineSnapshots.ts b/packages/jest-snapshot/src/InlineSnapshots.ts
index 2e5013784b4a..53d644e63c48 100644
--- a/packages/jest-snapshot/src/InlineSnapshots.ts
+++ b/packages/jest-snapshot/src/InlineSnapshots.ts
@@ -6,7 +6,7 @@
*/
import * as path from 'path';
-import type {PluginItem} from '@babel/core';
+import type {ParseResult, PluginItem} from '@babel/core';
import {Expression, File, Program, isAwaitExpression} from '@babel/types';
import * as fs from 'graceful-fs';
import type {
@@ -95,12 +95,39 @@ const saveSnapshotsForFile = (
// by one to formatting parser.
const snapshotMatcherNames: Array = [];
- const ast = parseSync(sourceFile, {
- filename: sourceFilePath,
- plugins,
- presets,
- root: rootDir,
- });
+ let ast: ParseResult | null = null;
+
+ try {
+ ast = parseSync(sourceFile, {
+ filename: sourceFilePath,
+ plugins,
+ presets,
+ root: rootDir,
+ });
+ } catch (error: any) {
+ // attempt to recover from missing jsx plugin
+ if (error.message.includes('@babel/plugin-syntax-jsx')) {
+ try {
+ const jsxSyntaxPlugin: PluginItem = [
+ require.resolve('@babel/plugin-syntax-jsx'),
+ {},
+ // unique name to make sure Babel does not complain about a possible duplicate plugin.
+ 'JSX syntax plugin added by Jest snapshot',
+ ];
+ ast = parseSync(sourceFile, {
+ filename: sourceFilePath,
+ plugins: [...plugins, jsxSyntaxPlugin],
+ presets,
+ root: rootDir,
+ });
+ } catch {
+ throw error;
+ }
+ } else {
+ throw error;
+ }
+ }
+
if (!ast) {
throw new Error(`jest-snapshot: Failed to parse ${sourceFilePath}`);
}
diff --git a/yarn.lock b/yarn.lock
index baa8f88f55b2..815500a8368d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1030,7 +1030,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.18.6":
+"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2":
version: 7.18.6
resolution: "@babel/plugin-syntax-jsx@npm:7.18.6"
dependencies:
@@ -12847,6 +12847,7 @@ __metadata:
dependencies:
"@babel/core": ^7.11.6
"@babel/generator": ^7.7.2
+ "@babel/plugin-syntax-jsx": ^7.7.2
"@babel/plugin-syntax-typescript": ^7.7.2
"@babel/preset-flow": ^7.7.2
"@babel/preset-react": ^7.12.1