feat(misc): replace ts-jest transformer with @swc/jest for ts solution setup (#29763)

## Current Behavior

## Expected Behavior

## Related Issue(s)

Fixes #
This commit is contained in:
Leosvel Pérez Espinosa 2025-01-28 11:51:25 +01:00 committed by GitHub
parent 5127c15871
commit 626c514a99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 480 additions and 43 deletions

View File

@ -252,11 +252,8 @@ describe('detox application generator', () => {
expect(tree.exists('my-dir/my-app-e2e/.detoxrc.json')).toBeTruthy(); expect(tree.exists('my-dir/my-app-e2e/.detoxrc.json')).toBeTruthy();
expect(tree.exists('my-dir/my-app-e2e/src/app.spec.ts')).toBeTruthy(); expect(tree.exists('my-dir/my-app-e2e/src/app.spec.ts')).toBeTruthy();
const detoxrc = tree.read('my-dir/my-app-e2e/.detoxrc.json').toString(); const detoxrcJson = readJson(tree, 'my-dir/my-app-e2e/.detoxrc.json');
// Strip trailing commas expect(detoxrcJson.testRunner.args.config).toEqual('./jest.config.json');
const detoxrcJson = JSON.parse(
detoxrc.replace(/(?<=(true|false|null|["\d}\]])\s*),(?=\s*[}\]])/g, '')
);
const appsDetoxrcJson = detoxrcJson['apps']; const appsDetoxrcJson = detoxrcJson['apps'];
expect(appsDetoxrcJson).toEqual({ expect(appsDetoxrcJson).toEqual({
'android.debug': { 'android.debug': {
@ -288,6 +285,32 @@ describe('detox application generator', () => {
type: 'ios.app', type: 'ios.app',
}, },
}); });
expect(tree.read('my-dir/my-app-e2e/jest.config.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"preset": "../../jest.preset",
"rootDir": ".",
"testMatch": [
"<rootDir>/src/**/*.test.ts?(x)",
"<rootDir>/src/**/*.spec.ts?(x)"
],
"testTimeout": 120000,
"maxWorkers": 1,
"globalSetup": "detox/runners/jest/globalSetup",
"globalTeardown": "detox/runners/jest/globalTeardown",
"reporters": ["detox/runners/jest/reporter"],
"testEnvironment": "detox/runners/jest/testEnvironment",
"verbose": true,
"setupFilesAfterEnv": ["<rootDir>/test-setup.ts"],
"transform": {
"^.+\\\\.(ts|js|html)$": [
"ts-jest",
{ "tsconfig": "<rootDir>/tsconfig.e2e.json" }
]
}
}
"
`);
}); });
it('should update configuration', async () => { it('should update configuration', async () => {
@ -558,5 +581,84 @@ describe('detox application generator', () => {
" "
`); `);
}); });
it('should generate jest test config with @swc/jest', async () => {
writeJson(tree, 'apps/my-app/package.json', {
name: 'my-app',
});
await detoxApplicationGenerator(tree, {
e2eDirectory: 'apps/my-app-e2e',
appProject: 'my-app',
linter: Linter.None,
framework: 'react-native',
addPlugin: true,
skipFormat: true,
});
expect(tree.exists('apps/my-app-e2e/test-setup.ts')).toBeTruthy();
const detoxrc = readJson(tree, 'apps/my-app-e2e/.detoxrc.json');
expect(detoxrc.testRunner.args.config).toEqual('./jest.config.ts');
expect(tree.read('apps/my-app-e2e/jest.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(\`\${__dirname}/.spec.swcrc\`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
export default {
preset: "../../jest.preset",
rootDir: ".",
testMatch: [
"<rootDir>/src/**/*.test.ts?(x)",
"<rootDir>/src/**/*.spec.ts?(x)"
],
testTimeout: 120000,
maxWorkers: 1,
globalSetup: "detox/runners/jest/globalSetup",
globalTeardown: "detox/runners/jest/globalTeardown",
reporters: ["detox/runners/jest/reporter"],
testEnvironment: "detox/runners/jest/testEnvironment",
verbose: true,
setupFilesAfterEnv: ["<rootDir>/test-setup.ts"],
transform: {
"^.+\\\\.(ts|js|html)$": ['@swc/jest', swcJestConfig]
}
};
"
`);
expect(tree.read('apps/my-app-e2e/.spec.swcrc', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
"
`);
});
}); });
}); });

View File

@ -2,7 +2,7 @@
"testRunner": { "testRunner": {
"args": { "args": {
"$0": "jest", "$0": "jest",
"config": "./jest.config.json" "config": "./<%= jestConfigFileName %>"
}, },
"jest": { "jest": {
"setupTimeout": 120000 "setupTimeout": 120000

View File

@ -13,11 +13,10 @@
"testEnvironment": "detox/runners/jest/testEnvironment", "testEnvironment": "detox/runners/jest/testEnvironment",
"verbose": true, "verbose": true,
"setupFilesAfterEnv": ["<rootDir>/test-setup.ts"], "setupFilesAfterEnv": ["<rootDir>/test-setup.ts"],
"transform": { "transform": {
"^.+\\.(ts|js|html)$": [ "^.+\\.(ts|js|html)$": [
"ts-jest", "ts-jest",
{ "tsconfig": "<rootDir>/tsconfig.e2e.json" } { "tsconfig": "<rootDir>/tsconfig.e2e.json" }
] ]
} }
} }

View File

@ -0,0 +1,30 @@
/* eslint-disable */
<% if (js) { %>const { readFileSync } = require('fs')<% } else { %>import { readFileSync } from 'fs';<% } %>
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
<% if (js) { %>module.exports =<% } else { %>export default<% } %> {
preset: "<%= offsetFromRoot %>jest.preset",
rootDir: ".",
testMatch: [
"<rootDir>/src/**/*.test.ts?(x)",
"<rootDir>/src/**/*.spec.ts?(x)"
],
testTimeout: 120000,
maxWorkers: 1,
globalSetup: "detox/runners/jest/globalSetup",
globalTeardown: "detox/runners/jest/globalTeardown",
reporters: ["detox/runners/jest/reporter"],
testEnvironment: "detox/runners/jest/testEnvironment",
verbose: true,
setupFilesAfterEnv: ["<rootDir>/test-setup.ts"],
transform: {
"^.+\\.(ts|js|html)$": ['@swc/jest', swcJestConfig]
}
};

View File

@ -28,6 +28,7 @@ describe('Create Files', () => {
expect(tree.exists('apps/my-app-e2e/.detoxrc.json')).toBeTruthy(); expect(tree.exists('apps/my-app-e2e/.detoxrc.json')).toBeTruthy();
expect(tree.exists('apps/my-app-e2e/tsconfig.json')).toBeTruthy(); expect(tree.exists('apps/my-app-e2e/tsconfig.json')).toBeTruthy();
expect(tree.exists('apps/my-app-e2e/tsconfig.e2e.json')).toBeTruthy(); expect(tree.exists('apps/my-app-e2e/tsconfig.e2e.json')).toBeTruthy();
expect(tree.exists('apps/my-app-e2e/jest.config.json')).toBeTruthy();
expect(tree.exists('apps/my-app-e2e/test-setup.ts')).toBeTruthy(); expect(tree.exists('apps/my-app-e2e/test-setup.ts')).toBeTruthy();
}); });
}); });

View File

@ -1,14 +1,15 @@
import { import {
offsetFromRoot as _offsetFromRoot,
detectPackageManager, detectPackageManager,
generateFiles, generateFiles,
getPackageManagerCommand, getPackageManagerCommand,
offsetFromRoot as _offsetFromRoot, joinPathFragments,
toJS, toJS,
Tree, Tree,
writeJson, writeJson,
joinPathFragments,
} from '@nx/devkit'; } from '@nx/devkit';
import { getRelativePathToRootTsConfig } from '@nx/js'; import { getRelativePathToRootTsConfig } from '@nx/js';
import { addSwcTestConfig } from '@nx/js/src/utils/swc/add-swc-config';
import { join } from 'path'; import { join } from 'path';
import { NormalizedSchema } from './normalize-options'; import { NormalizedSchema } from './normalize-options';
@ -23,8 +24,22 @@ export function createFiles(host: Tree, options: NormalizedSchema) {
exec: getPackageManagerCommand(detectPackageManager(host.root)).exec, exec: getPackageManagerCommand(detectPackageManager(host.root)).exec,
offsetFromRoot, offsetFromRoot,
rootTsConfigPath, rootTsConfigPath,
jestConfigFileName: options.isUsingTsSolutionConfig
? 'jest.config.ts'
: 'jest.config.json',
}); });
if (options.isUsingTsSolutionConfig) { if (options.isUsingTsSolutionConfig) {
addSwcTestConfig(host, options.e2eProjectRoot, 'es6');
generateFiles(
host,
join(__dirname, '../files/ts-solution'),
options.e2eProjectRoot,
{
...options,
exec: getPackageManagerCommand(detectPackageManager(host.root)).exec,
offsetFromRoot,
}
);
writeJson( writeJson(
host, host,
joinPathFragments(options.e2eProjectRoot, 'tsconfig.json'), joinPathFragments(options.e2eProjectRoot, 'tsconfig.json'),

View File

@ -39,6 +39,7 @@ describe('Normalize Options', () => {
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
isUsingTsSolutionConfig: false, isUsingTsSolutionConfig: false,
linter: Linter.EsLint, linter: Linter.EsLint,
js: false,
}); });
}); });
@ -68,6 +69,7 @@ describe('Normalize Options', () => {
e2eProjectRoot: 'apps/my-app-e2e', e2eProjectRoot: 'apps/my-app-e2e',
framework: 'react-native', framework: 'react-native',
isUsingTsSolutionConfig: false, isUsingTsSolutionConfig: false,
js: false,
}); });
}); });
@ -97,6 +99,7 @@ describe('Normalize Options', () => {
e2eProjectName: 'directory-my-app-e2e', e2eProjectName: 'directory-my-app-e2e',
framework: 'react-native', framework: 'react-native',
isUsingTsSolutionConfig: false, isUsingTsSolutionConfig: false,
js: false,
}); });
}); });
}); });

View File

@ -48,5 +48,6 @@ export async function normalizeOptions(
e2eProjectName, e2eProjectName,
e2eProjectRoot, e2eProjectRoot,
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host), isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
js: options.js ?? false,
}; };
} }

View File

@ -45,6 +45,43 @@ describe('e2eProjectGenerator', () => {
expect(tree.exists(`e2e/src/server/server.spec.ts`)).toBeTruthy(); expect(tree.exists(`e2e/src/server/server.spec.ts`)).toBeTruthy();
}); });
it('should generate jest test config with ts-jest for server app', async () => {
await applicationGenerator(tree, {
directory: 'api',
framework: 'none',
e2eTestRunner: 'none',
addPlugin: true,
});
await e2eProjectGenerator(tree, {
projectType: 'server',
project: 'api',
addPlugin: true,
});
expect(tree.read('api-e2e/jest.config.ts', 'utf-8')).toMatchInlineSnapshot(`
"export default {
displayName: 'api-e2e',
preset: '../jest.preset.js',
globalSetup: '<rootDir>/src/support/global-setup.ts',
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/api-e2e',
};
"
`);
expect(tree.exists('api-e2e/.spec.swcrc')).toBeFalsy();
});
it('should generate cli project', async () => { it('should generate cli project', async () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
directory: 'api', directory: 'api',
@ -75,6 +112,41 @@ describe('e2eProjectGenerator', () => {
`); `);
}); });
it('should generate jest test config with ts-jest for cli project', async () => {
await applicationGenerator(tree, {
directory: 'cli',
framework: 'none',
e2eTestRunner: 'none',
addPlugin: true,
});
await e2eProjectGenerator(tree, {
projectType: 'cli',
project: 'cli',
addPlugin: true,
});
expect(tree.read('cli-e2e/jest.config.ts', 'utf-8')).toMatchInlineSnapshot(`
"export default {
displayName: 'cli-e2e',
preset: '../jest.preset.js',
setupFiles: ['<rootDir>/src/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/cli-e2e',
};
"
`);
expect(tree.exists('cli-e2e/.spec.swcrc')).toBeFalsy();
});
describe('TS solution setup', () => { describe('TS solution setup', () => {
beforeEach(() => { beforeEach(() => {
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
@ -118,28 +190,6 @@ describe('e2eProjectGenerator', () => {
}, },
] ]
`); `);
expect(tree.read('api-e2e/jest.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"export default {
displayName: 'api-e2e',
preset: '../jest.preset.js',
globalSetup: '<rootDir>/src/support/global-setup.ts',
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.json',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/api-e2e',
};
"
`);
expect(readJson(tree, 'api-e2e/tsconfig.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'api-e2e/tsconfig.json')).toMatchInlineSnapshot(`
{ {
"compilerOptions": { "compilerOptions": {
@ -157,5 +207,139 @@ describe('e2eProjectGenerator', () => {
} }
`); `);
}); });
it('should generate jest test config with @swc/jest for server app', async () => {
await applicationGenerator(tree, {
directory: 'api',
framework: 'none',
e2eTestRunner: 'none',
addPlugin: true,
});
await e2eProjectGenerator(tree, {
projectType: 'server',
project: 'api',
addPlugin: true,
});
expect(tree.read('api-e2e/jest.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(\`\${__dirname}/.spec.swcrc\`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
export default {
displayName: 'api-e2e',
preset: '../jest.preset.js',
globalSetup: '<rootDir>/src/support/global-setup.ts',
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: 'test-output/jest/coverage',
};
"
`);
expect(tree.read('api-e2e/.spec.swcrc', 'utf-8')).toMatchInlineSnapshot(`
"{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
"
`);
});
it('should generate jest test config with @swc/jest for cli project', async () => {
await applicationGenerator(tree, {
directory: 'cli',
framework: 'none',
e2eTestRunner: 'none',
addPlugin: true,
});
await e2eProjectGenerator(tree, {
projectType: 'cli',
project: 'cli',
addPlugin: true,
});
expect(tree.read('cli-e2e/jest.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(\`\${__dirname}/.spec.swcrc\`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
export default {
displayName: 'cli-e2e',
preset: '../jest.preset.js',
setupFiles: ['<rootDir>/src/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: 'test-output/jest/coverage',
};
"
`);
expect(tree.read('cli-e2e/.spec.swcrc', 'utf-8')).toMatchInlineSnapshot(`
"{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
"
`);
});
}); });
}); });

View File

@ -36,6 +36,7 @@ import {
} from '@nx/js/src/utils/typescript/ts-solution-setup'; } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { getImportPath } from '@nx/js/src/utils/get-import-path'; import { getImportPath } from '@nx/js/src/utils/get-import-path';
import { relative } from 'node:path/posix'; import { relative } from 'node:path/posix';
import { addSwcTestConfig } from '@nx/js/src/utils/swc/add-swc-config';
export async function e2eProjectGenerator(host: Tree, options: Schema) { export async function e2eProjectGenerator(host: Tree, options: Schema) {
return await e2eProjectGeneratorInternal(host, { return await e2eProjectGeneratorInternal(host, {
@ -126,6 +127,10 @@ export async function e2eProjectGeneratorInternal(
const tsConfigFile = isUsingTsSolutionConfig const tsConfigFile = isUsingTsSolutionConfig
? 'tsconfig.json' ? 'tsconfig.json'
: 'tsconfig.spec.json'; : 'tsconfig.spec.json';
const rootOffset = offsetFromRoot(options.e2eProjectRoot);
const coverageDirectory = isUsingTsSolutionConfig
? 'test-output/jest/coverage'
: joinPathFragments(rootOffset, 'coverage', options.e2eProjectName);
if (options.projectType === 'server') { if (options.projectType === 'server') {
generateFiles( generateFiles(
host, host,
@ -135,8 +140,10 @@ export async function e2eProjectGeneratorInternal(
...options, ...options,
...names(options.rootProject ? 'server' : options.project), ...names(options.rootProject ? 'server' : options.project),
tsConfigFile, tsConfigFile,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot: rootOffset,
jestPreset, jestPreset,
coverageDirectory,
isUsingTsSolutionConfig,
tmpl: '', tmpl: '',
} }
); );
@ -150,7 +157,7 @@ export async function e2eProjectGeneratorInternal(
...options, ...options,
...names(options.rootProject ? 'server' : options.project), ...names(options.rootProject ? 'server' : options.project),
tsConfigFile, tsConfigFile,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot: rootOffset,
tmpl: '', tmpl: '',
} }
); );
@ -166,14 +173,17 @@ export async function e2eProjectGeneratorInternal(
...names(options.rootProject ? 'cli' : options.project), ...names(options.rootProject ? 'cli' : options.project),
mainFile, mainFile,
tsConfigFile, tsConfigFile,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot: rootOffset,
jestPreset, jestPreset,
coverageDirectory,
isUsingTsSolutionConfig,
tmpl: '', tmpl: '',
} }
); );
} }
if (isUsingTsSolutionConfig) { if (isUsingTsSolutionConfig) {
addSwcTestConfig(host, options.e2eProjectRoot, 'es6');
generateFiles( generateFiles(
host, host,
path.join(__dirname, 'files/ts-solution'), path.join(__dirname, 'files/ts-solution'),
@ -184,7 +194,7 @@ export async function e2eProjectGeneratorInternal(
options.e2eProjectRoot, options.e2eProjectRoot,
appProject.root appProject.root
), ),
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot: rootOffset,
tmpl: '', tmpl: '',
} }
); );
@ -195,7 +205,7 @@ export async function e2eProjectGeneratorInternal(
options.e2eProjectRoot, options.e2eProjectRoot,
{ {
...options, ...options,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot: rootOffset,
tmpl: '', tmpl: '',
} }
); );

View File

@ -1,13 +1,26 @@
<%_ if (isUsingTsSolutionConfig) { _%>
/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
<%_ } _%>
export default { export default {
displayName: '<%= e2eProjectName %>', displayName: '<%= e2eProjectName %>',
preset: '<%= offsetFromRoot %><%= jestPreset %>', preset: '<%= offsetFromRoot %><%= jestPreset %>',
setupFiles: ['<rootDir>/src/test-setup.ts'], setupFiles: ['<rootDir>/src/test-setup.ts'],
testEnvironment: 'node', testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]s$': ['ts-jest', { '^.+\\.[tj]s$': <% if (isUsingTsSolutionConfig) { %>['@swc/jest', swcJestConfig]<% } else { %>['ts-jest', {
tsconfig: '<rootDir>/<%= tsConfigFile %>', tsconfig: '<rootDir>/<%= tsConfigFile %>',
}], }]<% } %>,
}, },
moduleFileExtensions: ['ts', 'js', 'html'], moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= e2eProjectName %>', coverageDirectory: '<%= coverageDirectory %>',
}; };

View File

@ -1,3 +1,16 @@
<%_ if (isUsingTsSolutionConfig) { _%>
/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
<%_ } _%>
export default { export default {
displayName: '<%= e2eProjectName %>', displayName: '<%= e2eProjectName %>',
preset: '<%= offsetFromRoot %><%= jestPreset %>', preset: '<%= offsetFromRoot %><%= jestPreset %>',
@ -6,10 +19,10 @@ export default {
setupFiles: ['<rootDir>/src/support/test-setup.ts'], setupFiles: ['<rootDir>/src/support/test-setup.ts'],
testEnvironment: 'node', testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]s$': ['ts-jest', { '^.+\\.[tj]s$': <% if (isUsingTsSolutionConfig) { %>['@swc/jest', swcJestConfig]<% } else { %>['ts-jest', {
tsconfig: '<rootDir>/<%= tsConfigFile %>', tsconfig: '<rootDir>/<%= tsConfigFile %>',
}], }]<% } %>,
}, },
moduleFileExtensions: ['ts', 'js', 'html'], moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= e2eProjectName %>', coverageDirectory: '<%= coverageDirectory %>',
}; };

View File

@ -587,6 +587,71 @@ describe('Remix Application', () => {
JSON.parse(tree.read('myapp/package.json', 'utf-8')) JSON.parse(tree.read('myapp/package.json', 'utf-8'))
).not.toThrow(); ).not.toThrow();
}); });
it('should generate jest test config with @swc/jest', async () => {
await applicationGenerator(tree, {
directory: 'myapp',
unitTestRunner: 'jest',
addPlugin: true,
skipFormat: true,
});
expect(tree.exists('myapp/tsconfig.spec.json')).toBeTruthy();
expect(tree.exists('myapp/tests/routes/_index.spec.tsx')).toBeTruthy();
expect(tree.exists('myapp/jest.config.ts')).toBeTruthy();
expect(tree.read('myapp/jest.config.ts', 'utf-8')).toMatchInlineSnapshot(`
"/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(\`\${__dirname}/.spec.swcrc\`, 'utf-8')
);
// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;
export default {
displayName: '@proj/myapp',
preset: '../jest.preset.js',
transform: {
'^.+\\\\.[tj]sx?$': ['@swc/jest', swcJestConfig]
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: 'test-output/jest/coverage'
};
"
`);
expect(tree.read('myapp/.spec.swcrc', 'utf-8')).toMatchInlineSnapshot(`
"{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true,
"tsx": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true,
"react": {
"runtime": "automatic"
}
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
"
`);
});
}); });
}); });

View File

@ -207,6 +207,7 @@ export async function remixApplicationGeneratorInternal(
skipPackageJson: false, skipPackageJson: false,
skipFormat: true, skipFormat: true,
addPlugin: true, addPlugin: true,
compiler: options.useTsSolution ? 'swc' : undefined,
}); });
const projectConfig = readProjectConfiguration(tree, options.projectName); const projectConfig = readProjectConfiguration(tree, options.projectName);
if (projectConfig.targets?.['test']?.options) { if (projectConfig.targets?.['test']?.options) {