diff --git a/packages/detox/src/generators/application/application.spec.ts b/packages/detox/src/generators/application/application.spec.ts index bdc3e772540ae..3d8dc6b31b4f7 100644 --- a/packages/detox/src/generators/application/application.spec.ts +++ b/packages/detox/src/generators/application/application.spec.ts @@ -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/src/app.spec.ts')).toBeTruthy(); - const detoxrc = tree.read('my-dir/my-app-e2e/.detoxrc.json').toString(); - // Strip trailing commas - const detoxrcJson = JSON.parse( - detoxrc.replace(/(?<=(true|false|null|["\d}\]])\s*),(?=\s*[}\]])/g, '') - ); + const detoxrcJson = readJson(tree, 'my-dir/my-app-e2e/.detoxrc.json'); + expect(detoxrcJson.testRunner.args.config).toEqual('./jest.config.json'); const appsDetoxrcJson = detoxrcJson['apps']; expect(appsDetoxrcJson).toEqual({ 'android.debug': { @@ -288,6 +285,32 @@ describe('detox application generator', () => { type: 'ios.app', }, }); + expect(tree.read('my-dir/my-app-e2e/jest.config.json', 'utf-8')) + .toMatchInlineSnapshot(` + "{ + "preset": "../../jest.preset", + "rootDir": ".", + "testMatch": [ + "/src/**/*.test.ts?(x)", + "/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": ["/test-setup.ts"], + "transform": { + "^.+\\\\.(ts|js|html)$": [ + "ts-jest", + { "tsconfig": "/tsconfig.e2e.json" } + ] + } + } + " + `); }); 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: [ + "/src/**/*.test.ts?(x)", + "/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: ["/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": [] + } + " + `); + }); }); }); diff --git a/packages/detox/src/generators/application/files/app/.detoxrc.json.template b/packages/detox/src/generators/application/files/app/.detoxrc.json.template index 01d9f72d300de..4393e053e8cf0 100644 --- a/packages/detox/src/generators/application/files/app/.detoxrc.json.template +++ b/packages/detox/src/generators/application/files/app/.detoxrc.json.template @@ -2,7 +2,7 @@ "testRunner": { "args": { "$0": "jest", - "config": "./jest.config.json" + "config": "./<%= jestConfigFileName %>" }, "jest": { "setupTimeout": 120000 diff --git a/packages/detox/src/generators/application/files/app/jest.config.json.template b/packages/detox/src/generators/application/files/non-ts-solution/jest.config.json.template similarity index 96% rename from packages/detox/src/generators/application/files/app/jest.config.json.template rename to packages/detox/src/generators/application/files/non-ts-solution/jest.config.json.template index 8a1f3a0057729..3987269ffb553 100644 --- a/packages/detox/src/generators/application/files/app/jest.config.json.template +++ b/packages/detox/src/generators/application/files/non-ts-solution/jest.config.json.template @@ -13,11 +13,10 @@ "testEnvironment": "detox/runners/jest/testEnvironment", "verbose": true, "setupFilesAfterEnv": ["/test-setup.ts"], - "transform": { + "transform": { "^.+\\.(ts|js|html)$": [ "ts-jest", { "tsconfig": "/tsconfig.e2e.json" } ] } - } diff --git a/packages/detox/src/generators/application/files/ts-solution/jest.config.ts.template b/packages/detox/src/generators/application/files/ts-solution/jest.config.ts.template new file mode 100644 index 0000000000000..d0156319568c7 --- /dev/null +++ b/packages/detox/src/generators/application/files/ts-solution/jest.config.ts.template @@ -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: [ + "/src/**/*.test.ts?(x)", + "/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: ["/test-setup.ts"], + transform: { + "^.+\\.(ts|js|html)$": ['@swc/jest', swcJestConfig] + } +}; diff --git a/packages/detox/src/generators/application/lib/create-files.spec.ts b/packages/detox/src/generators/application/lib/create-files.spec.ts index 31effd55eb844..85110b09e402a 100644 --- a/packages/detox/src/generators/application/lib/create-files.spec.ts +++ b/packages/detox/src/generators/application/lib/create-files.spec.ts @@ -28,6 +28,7 @@ describe('Create Files', () => { 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.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(); }); }); diff --git a/packages/detox/src/generators/application/lib/create-files.ts b/packages/detox/src/generators/application/lib/create-files.ts index 0eee321dec103..7c0bce21a3eaf 100644 --- a/packages/detox/src/generators/application/lib/create-files.ts +++ b/packages/detox/src/generators/application/lib/create-files.ts @@ -1,14 +1,15 @@ import { + offsetFromRoot as _offsetFromRoot, detectPackageManager, generateFiles, getPackageManagerCommand, - offsetFromRoot as _offsetFromRoot, + joinPathFragments, toJS, Tree, writeJson, - joinPathFragments, } from '@nx/devkit'; import { getRelativePathToRootTsConfig } from '@nx/js'; +import { addSwcTestConfig } from '@nx/js/src/utils/swc/add-swc-config'; import { join } from 'path'; import { NormalizedSchema } from './normalize-options'; @@ -23,8 +24,22 @@ export function createFiles(host: Tree, options: NormalizedSchema) { exec: getPackageManagerCommand(detectPackageManager(host.root)).exec, offsetFromRoot, rootTsConfigPath, + jestConfigFileName: options.isUsingTsSolutionConfig + ? 'jest.config.ts' + : 'jest.config.json', }); 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( host, joinPathFragments(options.e2eProjectRoot, 'tsconfig.json'), diff --git a/packages/detox/src/generators/application/lib/normalize-options.spec.ts b/packages/detox/src/generators/application/lib/normalize-options.spec.ts index e1d78326694aa..ca5fc8301082e 100644 --- a/packages/detox/src/generators/application/lib/normalize-options.spec.ts +++ b/packages/detox/src/generators/application/lib/normalize-options.spec.ts @@ -39,6 +39,7 @@ describe('Normalize Options', () => { appRoot: 'apps/my-app', isUsingTsSolutionConfig: false, linter: Linter.EsLint, + js: false, }); }); @@ -68,6 +69,7 @@ describe('Normalize Options', () => { e2eProjectRoot: 'apps/my-app-e2e', framework: 'react-native', isUsingTsSolutionConfig: false, + js: false, }); }); @@ -97,6 +99,7 @@ describe('Normalize Options', () => { e2eProjectName: 'directory-my-app-e2e', framework: 'react-native', isUsingTsSolutionConfig: false, + js: false, }); }); }); diff --git a/packages/detox/src/generators/application/lib/normalize-options.ts b/packages/detox/src/generators/application/lib/normalize-options.ts index 3c77232e03f99..ed8868d94f9c5 100644 --- a/packages/detox/src/generators/application/lib/normalize-options.ts +++ b/packages/detox/src/generators/application/lib/normalize-options.ts @@ -48,5 +48,6 @@ export async function normalizeOptions( e2eProjectName, e2eProjectRoot, isUsingTsSolutionConfig: isUsingTsSolutionSetup(host), + js: options.js ?? false, }; } diff --git a/packages/node/src/generators/e2e-project/e2e-project.spec.ts b/packages/node/src/generators/e2e-project/e2e-project.spec.ts index beab2e8b32340..97df848f1d08e 100644 --- a/packages/node/src/generators/e2e-project/e2e-project.spec.ts +++ b/packages/node/src/generators/e2e-project/e2e-project.spec.ts @@ -45,6 +45,43 @@ describe('e2eProjectGenerator', () => { 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: '/src/support/global-setup.ts', + globalTeardown: '/src/support/global-teardown.ts', + setupFiles: ['/src/support/test-setup.ts'], + testEnvironment: 'node', + transform: { + '^.+\\\\.[tj]s$': [ + 'ts-jest', + { + tsconfig: '/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 () => { await applicationGenerator(tree, { 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: ['/src/test-setup.ts'], + testEnvironment: 'node', + transform: { + '^.+\\\\.[tj]s$': [ + 'ts-jest', + { + tsconfig: '/tsconfig.spec.json', + }, + ], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../coverage/cli-e2e', + }; + " + `); + expect(tree.exists('cli-e2e/.spec.swcrc')).toBeFalsy(); + }); + describe('TS solution setup', () => { beforeEach(() => { tree = createTreeWithEmptyWorkspace(); @@ -118,9 +190,51 @@ describe('e2eProjectGenerator', () => { }, ] `); + expect(readJson(tree, 'api-e2e/tsconfig.json')).toMatchInlineSnapshot(` + { + "compilerOptions": { + "esModuleInterop": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "outDir": "out-tsc/api-e2e", + }, + "extends": "../tsconfig.base.json", + "include": [ + "jest.config.ts", + "src/**/*.ts", + ], + "references": [], + } + `); + }); + + 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(` - "export default { + "/* 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: '/src/support/global-setup.ts', @@ -128,33 +242,103 @@ describe('e2eProjectGenerator', () => { setupFiles: ['/src/support/test-setup.ts'], testEnvironment: 'node', transform: { - '^.+\\\\.[tj]s$': [ - 'ts-jest', - { - tsconfig: '/tsconfig.json', - }, - ], + '^.+\\\\.[tj]s$': ['@swc/jest', swcJestConfig], }, moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../coverage/api-e2e', + coverageDirectory: 'test-output/jest/coverage', }; " `); - expect(readJson(tree, 'api-e2e/tsconfig.json')).toMatchInlineSnapshot(` - { - "compilerOptions": { - "esModuleInterop": true, - "noImplicitAny": false, - "noUnusedLocals": false, - "outDir": "out-tsc/api-e2e", + 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 }, - "extends": "../tsconfig.base.json", - "include": [ - "jest.config.ts", - "src/**/*.ts", - ], - "references": [], + "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: ['/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": [] + } + " `); }); }); diff --git a/packages/node/src/generators/e2e-project/e2e-project.ts b/packages/node/src/generators/e2e-project/e2e-project.ts index 0858b4dc7eb77..ce63c90165ce5 100644 --- a/packages/node/src/generators/e2e-project/e2e-project.ts +++ b/packages/node/src/generators/e2e-project/e2e-project.ts @@ -36,6 +36,7 @@ import { } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { getImportPath } from '@nx/js/src/utils/get-import-path'; 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) { return await e2eProjectGeneratorInternal(host, { @@ -126,6 +127,10 @@ export async function e2eProjectGeneratorInternal( const tsConfigFile = isUsingTsSolutionConfig ? 'tsconfig.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') { generateFiles( host, @@ -135,8 +140,10 @@ export async function e2eProjectGeneratorInternal( ...options, ...names(options.rootProject ? 'server' : options.project), tsConfigFile, - offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), + offsetFromRoot: rootOffset, jestPreset, + coverageDirectory, + isUsingTsSolutionConfig, tmpl: '', } ); @@ -150,7 +157,7 @@ export async function e2eProjectGeneratorInternal( ...options, ...names(options.rootProject ? 'server' : options.project), tsConfigFile, - offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), + offsetFromRoot: rootOffset, tmpl: '', } ); @@ -166,14 +173,17 @@ export async function e2eProjectGeneratorInternal( ...names(options.rootProject ? 'cli' : options.project), mainFile, tsConfigFile, - offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), + offsetFromRoot: rootOffset, jestPreset, + coverageDirectory, + isUsingTsSolutionConfig, tmpl: '', } ); } if (isUsingTsSolutionConfig) { + addSwcTestConfig(host, options.e2eProjectRoot, 'es6'); generateFiles( host, path.join(__dirname, 'files/ts-solution'), @@ -184,7 +194,7 @@ export async function e2eProjectGeneratorInternal( options.e2eProjectRoot, appProject.root ), - offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), + offsetFromRoot: rootOffset, tmpl: '', } ); @@ -195,7 +205,7 @@ export async function e2eProjectGeneratorInternal( options.e2eProjectRoot, { ...options, - offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), + offsetFromRoot: rootOffset, tmpl: '', } ); diff --git a/packages/node/src/generators/e2e-project/files/cli/jest.config.ts__tmpl__ b/packages/node/src/generators/e2e-project/files/cli/jest.config.ts__tmpl__ index fe96a5081ddf3..2096f403662b9 100644 --- a/packages/node/src/generators/e2e-project/files/cli/jest.config.ts__tmpl__ +++ b/packages/node/src/generators/e2e-project/files/cli/jest.config.ts__tmpl__ @@ -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 { displayName: '<%= e2eProjectName %>', preset: '<%= offsetFromRoot %><%= jestPreset %>', setupFiles: ['/src/test-setup.ts'], testEnvironment: 'node', transform: { - '^.+\\.[tj]s$': ['ts-jest', { + '^.+\\.[tj]s$': <% if (isUsingTsSolutionConfig) { %>['@swc/jest', swcJestConfig]<% } else { %>['ts-jest', { tsconfig: '/<%= tsConfigFile %>', - }], + }]<% } %>, }, moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '<%= offsetFromRoot %>coverage/<%= e2eProjectName %>', + coverageDirectory: '<%= coverageDirectory %>', }; diff --git a/packages/node/src/generators/e2e-project/files/server/common/jest.config.ts__tmpl__ b/packages/node/src/generators/e2e-project/files/server/common/jest.config.ts__tmpl__ index 329afa69d90f2..a5c4358f656e3 100644 --- a/packages/node/src/generators/e2e-project/files/server/common/jest.config.ts__tmpl__ +++ b/packages/node/src/generators/e2e-project/files/server/common/jest.config.ts__tmpl__ @@ -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 { displayName: '<%= e2eProjectName %>', preset: '<%= offsetFromRoot %><%= jestPreset %>', @@ -6,10 +19,10 @@ export default { setupFiles: ['/src/support/test-setup.ts'], testEnvironment: 'node', transform: { - '^.+\\.[tj]s$': ['ts-jest', { + '^.+\\.[tj]s$': <% if (isUsingTsSolutionConfig) { %>['@swc/jest', swcJestConfig]<% } else { %>['ts-jest', { tsconfig: '/<%= tsConfigFile %>', - }], + }]<% } %>, }, moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '<%= offsetFromRoot %>coverage/<%= e2eProjectName %>', + coverageDirectory: '<%= coverageDirectory %>', }; diff --git a/packages/remix/src/generators/application/application.impl.spec.ts b/packages/remix/src/generators/application/application.impl.spec.ts index 1b19774098b7a..7f8fff60010ab 100644 --- a/packages/remix/src/generators/application/application.impl.spec.ts +++ b/packages/remix/src/generators/application/application.impl.spec.ts @@ -587,6 +587,71 @@ describe('Remix Application', () => { JSON.parse(tree.read('myapp/package.json', 'utf-8')) ).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": [] + } + " + `); + }); }); }); diff --git a/packages/remix/src/generators/application/application.impl.ts b/packages/remix/src/generators/application/application.impl.ts index 3150f1d28e134..97cc6bd78575b 100644 --- a/packages/remix/src/generators/application/application.impl.ts +++ b/packages/remix/src/generators/application/application.impl.ts @@ -207,6 +207,7 @@ export async function remixApplicationGeneratorInternal( skipPackageJson: false, skipFormat: true, addPlugin: true, + compiler: options.useTsSolution ? 'swc' : undefined, }); const projectConfig = readProjectConfiguration(tree, options.projectName); if (projectConfig.targets?.['test']?.options) {