Skip to content

Commit d601561

Browse files
authored
feat(misc): use @swc/jest instead of ts-jest for the ts solution setup (#29718)
## Current Behavior When using the TS solution setup and `jest` is used, `ts-jest` is used as the transformer in most cases (except when the build compiler is `swc`). The `ts-jest` transformer doesn't support modern module resolutions like `nodenext` and it doesn't support TS project references either. ## Expected Behavior When using the TS solution setup and `jest` is used, `@swc/jest` should be used as the transformer in cases where previously `ts-jest` was being used and regardless of using `swc` as the build compiler. ## Related Issue(s) Fixes #
1 parent 4bbbea2 commit d601561

File tree

28 files changed

+1101
-87
lines changed

28 files changed

+1101
-87
lines changed

docs/generated/packages/jest/documents/overview.md

+31
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ export default async function () {
316316

317317
If you're using `@swc/jest` and a global setup/teardown file, you have to set the `noInterop: false` and use dynamic imports within the setup function:
318318

319+
{% tabs %}
320+
{% tab label="Using the config from .swcrc" %}
321+
319322
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
320323
/* eslint-disable */
321324
import { readFileSync } from 'fs';
@@ -344,6 +347,34 @@ export default {
344347
};
345348
```
346349

350+
{% /tab %}
351+
352+
{% tab label="Using the config from .spec.swcrc" %}
353+
354+
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
355+
/* eslint-disable */
356+
import { readFileSync } from 'fs';
357+
358+
// Reading the SWC compilation config for the spec files
359+
const swcJestConfig = JSON.parse(
360+
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
361+
);
362+
363+
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
364+
swcJestConfig.swcrc = false;
365+
366+
export default {
367+
globalSetup: '<rootDir>/src/global-setup-swc.ts',
368+
transform: {
369+
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
370+
},
371+
// other settings
372+
};
373+
```
374+
375+
{% /tab %}
376+
{% /tabs %}
377+
347378
```typescript {% fileName="global-setup-swc.ts" %}
348379
import { registerTsProject } from '@nx/js/src/internal';
349380
const cleanupRegisteredPaths = registerTsProject('./tsconfig.base.json');

docs/generated/packages/node/generators/application.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@
6969
},
7070
"swcJest": {
7171
"type": "boolean",
72-
"description": "Use `@swc/jest` instead `ts-jest` for faster test compilation.",
73-
"default": false
72+
"description": "Use `@swc/jest` instead `ts-jest` for faster test compilation."
7473
},
7574
"babelJest": {
7675
"type": "boolean",

docs/shared/packages/jest/jest-plugin.md

+31
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ export default async function () {
316316

317317
If you're using `@swc/jest` and a global setup/teardown file, you have to set the `noInterop: false` and use dynamic imports within the setup function:
318318

319+
{% tabs %}
320+
{% tab label="Using the config from .swcrc" %}
321+
319322
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
320323
/* eslint-disable */
321324
import { readFileSync } from 'fs';
@@ -344,6 +347,34 @@ export default {
344347
};
345348
```
346349

350+
{% /tab %}
351+
352+
{% tab label="Using the config from .spec.swcrc" %}
353+
354+
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
355+
/* eslint-disable */
356+
import { readFileSync } from 'fs';
357+
358+
// Reading the SWC compilation config for the spec files
359+
const swcJestConfig = JSON.parse(
360+
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
361+
);
362+
363+
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
364+
swcJestConfig.swcrc = false;
365+
366+
export default {
367+
globalSetup: '<rootDir>/src/global-setup-swc.ts',
368+
transform: {
369+
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
370+
},
371+
// other settings
372+
};
373+
```
374+
375+
{% /tab %}
376+
{% /tabs %}
377+
347378
```typescript {% fileName="global-setup-swc.ts" %}
348379
import { registerTsProject } from '@nx/js/src/internal';
349380
const cleanupRegisteredPaths = registerTsProject('./tsconfig.base.json');

packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.spec.ts

+91-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
readJson,
77
Tree,
88
updateJson,
9+
writeJson,
910
} from '@nx/devkit';
1011
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
1112
import {
@@ -70,10 +71,24 @@ describe('@nx/eslint:workspace-rules-project', () => {
7071
expect(tsConfig.extends).toBe('../../tsconfig.json');
7172
});
7273

73-
it('should create a project with a test target', async () => {
74+
it('should create the jest config using ts-jest', async () => {
7475
await lintWorkspaceRulesProjectGenerator(tree);
7576

7677
expect(tree.exists('tools/eslint-rules/jest.config.ts')).toBeTruthy();
78+
expect(tree.read('tools/eslint-rules/jest.config.ts', 'utf-8'))
79+
.toMatchInlineSnapshot(`
80+
"export default {
81+
displayName: 'eslint-rules',
82+
preset: '../../jest.preset.js',
83+
transform: {
84+
'^.+\\\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
85+
},
86+
moduleFileExtensions: ['ts', 'js', 'html'],
87+
coverageDirectory: '../../coverage/tools/eslint-rules',
88+
};
89+
"
90+
`);
91+
expect(tree.exists('tools/eslint-rules/.spec.swcrc')).toBeFalsy();
7792
});
7893

7994
it('should not update the required files if the project already exists', async () => {
@@ -104,4 +119,79 @@ describe('@nx/eslint:workspace-rules-project', () => {
104119
customTsconfigContents
105120
);
106121
});
122+
123+
describe('TS solution setup', () => {
124+
beforeEach(() => {
125+
tree = createTreeWithEmptyWorkspace();
126+
updateJson(tree, 'package.json', (json) => {
127+
json.workspaces = ['packages/*'];
128+
return json;
129+
});
130+
writeJson(tree, 'tsconfig.base.json', {
131+
compilerOptions: { composite: true },
132+
});
133+
writeJson(tree, 'tsconfig.json', {
134+
extends: './tsconfig.base.json',
135+
files: [],
136+
references: [],
137+
});
138+
});
139+
140+
it('should create the jest config using @swc/jest', async () => {
141+
await lintWorkspaceRulesProjectGenerator(tree);
142+
143+
expect(tree.exists('tools/eslint-rules/jest.config.ts')).toBeTruthy();
144+
expect(tree.read('tools/eslint-rules/jest.config.ts', 'utf-8'))
145+
.toMatchInlineSnapshot(`
146+
"/* eslint-disable */
147+
import { readFileSync } from 'fs';
148+
149+
// Reading the SWC compilation config for the spec files
150+
const swcJestConfig = JSON.parse(
151+
readFileSync(\`\${__dirname}/.spec.swcrc\`, 'utf-8')
152+
);
153+
154+
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
155+
swcJestConfig.swcrc = false;
156+
157+
export default {
158+
displayName: 'eslint-rules',
159+
preset: '../../jest.preset.js',
160+
transform: {
161+
'^.+\\\\.[tj]s$': ['@swc/jest', swcJestConfig],
162+
},
163+
moduleFileExtensions: ['ts', 'js', 'html'],
164+
coverageDirectory: 'test-output/jest/coverage',
165+
};
166+
"
167+
`);
168+
expect(tree.exists('tools/eslint-rules/.spec.swcrc')).toBeTruthy();
169+
expect(tree.read('tools/eslint-rules/.spec.swcrc', 'utf-8'))
170+
.toMatchInlineSnapshot(`
171+
"{
172+
"jsc": {
173+
"target": "es2017",
174+
"parser": {
175+
"syntax": "typescript",
176+
"decorators": true,
177+
"dynamicImport": true
178+
},
179+
"transform": {
180+
"decoratorMetadata": true,
181+
"legacyDecorator": true
182+
},
183+
"keepClassNames": true,
184+
"externalHelpers": true,
185+
"loose": true
186+
},
187+
"module": {
188+
"type": "es6"
189+
},
190+
"sourceMaps": true,
191+
"exclude": []
192+
}
193+
"
194+
`);
195+
});
196+
});
107197
});

packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from '@nx/devkit';
1616
import { getRelativePathToRootTsConfig } from '@nx/js';
1717
import { addSwcRegisterDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
18+
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
1819
import { join } from 'path';
1920
import { nxVersion, typescriptESLintVersion } from '../../utils/versions';
2021
import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules';
@@ -80,7 +81,7 @@ export async function lintWorkspaceRulesProjectGenerator(
8081
supportTsx: false,
8182
skipSerializers: true,
8283
setupFile: 'none',
83-
compiler: 'tsc',
84+
compiler: isUsingTsSolutionSetup(tree) ? 'swc' : 'tsc',
8485
skipFormat: true,
8586
})
8687
);

0 commit comments

Comments
 (0)