fix(testing): update v14 migration and migrate jest.config.ts to use export default (#10035)

* fix(testing): jest.preset.ts => jest.preset.js

* fix(testing): update to export default

* fix(testing): migration for moving to export default

* fix(testing): add eslint ignore comments for jest config properties

fixes: #10021

* fix(testing): update tsconfig.spec.json for next apps with project parserOptions

fixes: #9982

* fix(testing): prevent renaming root jest preset

fixes: #9973

* fix(testing): update snapshots for export default

* fix(testing): bump migration version to run

* fix(testing): make sure default jest tests pass for various projects

* fix(js): generate correct jest config for --compiler=swc --js
This commit is contained in:
Caleb Ukle 2022-05-11 13:04:29 -05:00 committed by GitHub
parent 4dbd6559cf
commit ecf88a6995
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 976 additions and 254 deletions

View File

@ -5,21 +5,17 @@ import {
runCLIAsync, runCLIAsync,
uniq, uniq,
updateFile, updateFile,
expectJestTestsToPass,
} from '@nrwl/e2e/utils'; } from '@nrwl/e2e/utils';
describe('Jest', () => { describe('Jest', () => {
beforeAll(() => { beforeAll(() => {
newProject({ name: uniq('proj') }); newProject({ name: uniq('proj-jest') });
}); });
it('should be able test projects using jest', async () => { it('should be able test projects using jest', async () => {
const mylib = uniq('mylib'); await expectJestTestsToPass('@nrwl/workspace:lib');
runCLI(`generate @nrwl/workspace:lib ${mylib} --unit-test-runner jest`); await expectJestTestsToPass('@nrwl/js:lib');
const libResult = await runCLIAsync(`test ${mylib}`);
expect(libResult.combinedOutput).toContain(
'Test Suites: 1 passed, 1 total'
);
}, 500000); }, 500000);
it('should merge with jest config globals', async () => { it('should merge with jest config globals', async () => {

View File

@ -1,5 +1,6 @@
import { import {
checkFilesExist, checkFilesExist,
expectJestTestsToPass,
checkFilesDoNotExist, checkFilesDoNotExist,
newProject, newProject,
readFile, readFile,
@ -242,4 +243,8 @@ describe('js e2e', () => {
checkFilesDoNotExist(`libs/${lib}/.babelrc`); checkFilesDoNotExist(`libs/${lib}/.babelrc`);
}); });
it('should run default jest tests', async () => {
await expectJestTestsToPass('@nrwl/js:lib');
});
}); });

View File

@ -3,6 +3,7 @@ import {
checkFilesExist, checkFilesExist,
cleanupProject, cleanupProject,
createFile, createFile,
expectJestTestsToPass,
isNotWindows, isNotWindows,
killPorts, killPorts,
newProject, newProject,
@ -409,6 +410,9 @@ describe('Next.js Applications', () => {
checkExport: false, checkExport: false,
}); });
}, 300000); }, 300000);
it('should run default jest tests', async () => {
await expectJestTestsToPass('@nrwl/next:app');
});
}); });
function getData(port: number, path = ''): Promise<any> { function getData(port: number, path = ''): Promise<any> {

View File

@ -2,6 +2,7 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
import { import {
checkFilesDoNotExist, checkFilesDoNotExist,
checkFilesExist, checkFilesExist,
expectJestTestsToPass,
killPorts, killPorts,
newProject, newProject,
packageInstall, packageInstall,
@ -359,9 +360,10 @@ describe('nest libraries', function () {
const jestConfigContent = readFile(`libs/${nestlib}/jest.config.ts`); const jestConfigContent = readFile(`libs/${nestlib}/jest.config.ts`);
expect(stripIndents`${jestConfigContent}`).toEqual( expect(stripIndents`${jestConfigContent}`).toEqual(
stripIndents`module.exports = { stripIndents`/* eslint-disable */
export default {
displayName: '${nestlib}', displayName: '${nestlib}',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -481,4 +483,8 @@ exports.FooModel = FooModel;
checkFilesDoNotExist('workspace.json', 'angular.json') checkFilesDoNotExist('workspace.json', 'angular.json')
).not.toThrow(); ).not.toThrow();
}, 1000000); }, 1000000);
it('should run default jest tests', async () => {
await expectJestTestsToPass('@nrwl/node:lib');
});
}); });

View File

@ -2,6 +2,7 @@ import {
checkFilesDoNotExist, checkFilesDoNotExist,
checkFilesExist, checkFilesExist,
createFile, createFile,
expectJestTestsToPass,
killPorts, killPorts,
newProject, newProject,
readFile, readFile,
@ -289,4 +290,9 @@ describe('React Applications and Libs with PostCSS', () => {
expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/); expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/);
expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/); expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/);
}, 250_000); }, 250_000);
it('should run default jest tests', async () => {
await expectJestTestsToPass('@nrwl/react:lib');
await expectJestTestsToPass('@nrwl/react:app');
});
}); });

View File

@ -881,3 +881,30 @@ export function waitUntil(
}, opts.timeout); }, opts.timeout);
}); });
} }
type GeneratorsWithDefaultTests =
| '@nrwl/js:lib'
| '@nrwl/node:lib'
| '@nrwl/react:lib'
| '@nrwl/react:app'
| '@nrwl/next:app'
| '@nrwl/angular:app'
| '@nrwl/workspace:lib'
| '@nrwl/web:app';
/**
* Runs the pass in generator and then runs test on
* the generated project to make sure the default tests pass.
*/
export async function expectJestTestsToPass(
generator: GeneratorsWithDefaultTests | string
) {
const name = uniq('proj');
const generatedResults = runCLI(
`generate ${generator} ${name} --no-interactive`
);
expect(generatedResults).toContain(`jest.config.ts`);
const results = await runCLIAsync(`test ${name}`);
expect(results.combinedOutput).toContain('Test Suites: 1 passed, 1 total');
}

View File

@ -14,6 +14,7 @@ import {
uniq, uniq,
updateFile, updateFile,
updateProjectConfig, updateProjectConfig,
expectJestTestsToPass,
} from '@nrwl/e2e/utils'; } from '@nrwl/e2e/utils';
describe('Web Components Applications', () => { describe('Web Components Applications', () => {
@ -186,6 +187,10 @@ describe('Web Components Applications', () => {
checkFilesDoNotExist('workspace.json', 'angular.json') checkFilesDoNotExist('workspace.json', 'angular.json')
).not.toThrow(); ).not.toThrow();
}, 1000000); }, 1000000);
it('should run default jest tests', async () => {
await expectJestTestsToPass('@nrwl/web:app');
});
}); });
describe('CLI - Environment Variables', () => { describe('CLI - Environment Variables', () => {

View File

@ -262,7 +262,7 @@ describe('move project', () => {
checkFilesExist(jestConfigPath); checkFilesExist(jestConfigPath);
const jestConfig = readFile(jestConfigPath); const jestConfig = readFile(jestConfigPath);
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`); expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
expect(jestConfig).toContain(`preset: '../../../../jest.preset.ts'`); expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`);
expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`); expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`);
const tsConfigPath = `${newPath}/tsconfig.json`; const tsConfigPath = `${newPath}/tsconfig.json`;
@ -399,7 +399,7 @@ describe('move project', () => {
checkFilesExist(jestConfigPath); checkFilesExist(jestConfigPath);
const jestConfig = readFile(jestConfigPath); const jestConfig = readFile(jestConfigPath);
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`); expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
expect(jestConfig).toContain(`preset: '../../../../jest.preset.ts'`); expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`);
expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`); expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`);
const tsConfigPath = `${newPath}/tsconfig.json`; const tsConfigPath = `${newPath}/tsconfig.json`;
@ -531,7 +531,7 @@ describe('move project', () => {
checkFilesExist(jestConfigPath); checkFilesExist(jestConfigPath);
const jestConfig = readFile(jestConfigPath); const jestConfig = readFile(jestConfigPath);
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`); expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
expect(jestConfig).toContain(`preset: '../../../../jest.preset.ts'`); expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`);
expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`); expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`);
const tsConfigPath = `${newPath}/tsconfig.json`; const tsConfigPath = `${newPath}/tsconfig.json`;

View File

@ -7,6 +7,7 @@ import {
runCLIAsync, runCLIAsync,
uniq, uniq,
updateFile, updateFile,
expectJestTestsToPass,
} from '@nrwl/e2e/utils'; } from '@nrwl/e2e/utils';
let proj: string; let proj: string;
@ -44,15 +45,8 @@ describe('@nrwl/workspace:library', () => {
}); });
describe('unit testing', () => { describe('unit testing', () => {
it('should support jest', async () => { it('should run default jest tests', async () => {
const libName = uniq('mylib'); await expectJestTestsToPass('@nrwl/workspace:lib');
runCLI(`generate @nrwl/workspace:lib ${libName}`);
const { stderr: result } = await runCLIAsync(`test ${libName}`);
expect(result).toContain(`Test Suites: 1 passed, 1 total`);
expect(result).toContain('Tests: 1 passed, 1 total');
}); });
}); });

View File

@ -55,7 +55,7 @@ Array [
"apps/one/two/test-ui-lib-e2e/src/support/index.ts", "apps/one/two/test-ui-lib-e2e/src/support/index.ts",
"apps/one/two/test-ui-lib-e2e/tsconfig.json", "apps/one/two/test-ui-lib-e2e/tsconfig.json",
"jest.config.ts", "jest.config.ts",
"jest.preset.ts", "jest.preset.js",
"libs/test-ui-lib/.eslintrc.json", "libs/test-ui-lib/.eslintrc.json",
"libs/test-ui-lib/.storybook/main.js", "libs/test-ui-lib/.storybook/main.js",
"libs/test-ui-lib/.storybook/preview.js", "libs/test-ui-lib/.storybook/preview.js",
@ -160,7 +160,7 @@ Array [
"apps/test-ui-lib-e2e/src/support/index.ts", "apps/test-ui-lib-e2e/src/support/index.ts",
"apps/test-ui-lib-e2e/tsconfig.json", "apps/test-ui-lib-e2e/tsconfig.json",
"jest.config.ts", "jest.config.ts",
"jest.preset.ts", "jest.preset.js",
"libs/test-ui-lib/.eslintrc.json", "libs/test-ui-lib/.eslintrc.json",
"libs/test-ui-lib/.storybook/main.js", "libs/test-ui-lib/.storybook/main.js",
"libs/test-ui-lib/.storybook/preview.js", "libs/test-ui-lib/.storybook/preview.js",

View File

@ -47,6 +47,12 @@
"cli": "nx", "cli": "nx",
"description": "Update move jest config files to .ts files.", "description": "Update move jest config files to .ts files.",
"factory": "./src/migrations/update-14-0-0/update-jest-config-ext" "factory": "./src/migrations/update-14-0-0/update-jest-config-ext"
},
"update-to-export-default": {
"version": "14.1.5-beta.0",
"cli": "nx",
"description": "Update to export default in jest config and revert jest.preset.ts to jest.preset.js",
"factory": "./src/migrations/update-14-1-5/update-exports-jest-config"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {

View File

@ -1 +1,3 @@
export = require('./jest-preset'); import { nxPreset } from './jest-preset';
export default nxPreset;

View File

@ -1,4 +1,4 @@
export = { export const nxPreset = {
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
resolver: '@nrwl/jest/plugins/resolver', resolver: '@nrwl/jest/plugins/resolver',
moduleFileExtensions: ['ts', 'js', 'mjs', 'html'], moduleFileExtensions: ['ts', 'js', 'mjs', 'html'],

View File

@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`jest should generate files 1`] = `
"import { getJestProjects } from '@nrwl/jest';
export default {
projects: getJestProjects()
};"
`;
exports[`jest should generate files 2`] = `
"const nxPreset = require('@nrwl/jest/preset').default;
module.exports = { ...nxPreset }"
`;
exports[`jest should generate files with --js flag 1`] = `
"const { getJestProjects } = require('@nrwl/jest');
module.exports = {
projects: getJestProjects()
};"
`;
exports[`jest should generate files with --js flag 2`] = `
"const nxPreset = require('@nrwl/jest/preset').default;
module.exports = { ...nxPreset }"
`;

View File

@ -1,4 +1,4 @@
import { readJson, Tree, writeJson } from '@nrwl/devkit'; import { readJson, stripIndents, Tree, writeJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { jestInitGenerator } from './init'; import { jestInitGenerator } from './init';
@ -9,17 +9,28 @@ describe('jest', () => {
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
}); });
it('should generate files', async () => { it('should generate files with --js flag', async () => {
jestInitGenerator(tree, { js: true });
expect(tree.exists('jest.config.js')).toBeTruthy();
expect(
stripIndents`${tree.read('jest.config.js', 'utf-8')}`
).toMatchSnapshot();
expect(
stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
).toMatchSnapshot();
});
it('should generate files ', async () => {
jestInitGenerator(tree, {}); jestInitGenerator(tree, {});
expect(tree.exists('jest.config.ts')).toBeTruthy(); expect(tree.exists('jest.config.ts')).toBeTruthy();
expect(tree.read('jest.config.ts', 'utf-8')).toMatchInlineSnapshot(` expect(
"const { getJestProjects } = require('@nrwl/jest'); stripIndents`${tree.read('jest.config.ts', 'utf-8')}`
).toMatchSnapshot();
module.exports = { expect(
projects: getJestProjects() stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
};" ).toMatchSnapshot();
`);
}); });
it('should not override existing files', async () => { it('should not override existing files', async () => {

View File

@ -29,22 +29,28 @@ const schemaDefaults = {
function createJestConfig(host: Tree, js: boolean = false) { function createJestConfig(host: Tree, js: boolean = false) {
// if the root ts config already exists then don't make a js one or vice versa // if the root ts config already exists then don't make a js one or vice versa
if (!host.exists('jest.config.ts') && !host.exists('jest.config.js')) { if (!host.exists('jest.config.ts') && !host.exists('jest.config.js')) {
host.write( const contents = js
`jest.config.${js ? 'js' : 'ts'}`, ? stripIndents`
stripIndents` const { getJestProjects } = require('@nrwl/jest');
const { getJestProjects } = require('@nrwl/jest');
module.exports = { module.exports = {
projects: getJestProjects() projects: getJestProjects()
};` };`
); : stripIndents`
import { getJestProjects } from '@nrwl/jest';
export default {
projects: getJestProjects()
};`;
host.write(`jest.config.${js ? 'js' : 'ts'}`, contents);
} }
if (!host.exists('jest.preset.ts') && !host.exists('jest.preset.js')) { if (!host.exists('jest.preset.js')) {
// preset is always js file.
host.write( host.write(
`jest.preset.${js ? 'js' : 'ts'}`, `jest.preset.js`,
` `
const nxPreset = require('@nrwl/jest/preset'); const nxPreset = require('@nrwl/jest/preset').default;
module.exports = { ...nxPreset }` module.exports = { ...nxPreset }`
); );

View File

@ -1,9 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`jestProject --babelJest should generate proper jest.transform when --compiler=swc and supportTsx is true 1`] = ` exports[`jestProject --babelJest should generate proper jest.transform when --compiler=swc and supportTsx is true 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'lib1', displayName: 'lib1',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
transform: { transform: {
'^.+\\\\\\\\.[tj]sx?$': ['@swc/jest', { jsc: { transform: { react: { runtime: 'automatic' } } } }] '^.+\\\\\\\\.[tj]sx?$': ['@swc/jest', { jsc: { transform: { react: { runtime: 'automatic' } } } }]
}, },
@ -14,9 +15,10 @@ exports[`jestProject --babelJest should generate proper jest.transform when --co
`; `;
exports[`jestProject --babelJest should generate proper jest.transform when babelJest and supportTsx is true 1`] = ` exports[`jestProject --babelJest should generate proper jest.transform when babelJest and supportTsx is true 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'lib1', displayName: 'lib1',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
transform: { transform: {
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest' '^.+\\\\\\\\.[tj]sx?$': 'babel-jest'
}, },
@ -27,9 +29,10 @@ exports[`jestProject --babelJest should generate proper jest.transform when babe
`; `;
exports[`jestProject --babelJest should generate proper jest.transform when babelJest is true 1`] = ` exports[`jestProject --babelJest should generate proper jest.transform when babelJest is true 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'lib1', displayName: 'lib1',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
transform: { transform: {
'^.+\\\\\\\\.[tj]s$': 'babel-jest' '^.+\\\\\\\\.[tj]s$': 'babel-jest'
}, },
@ -40,9 +43,10 @@ exports[`jestProject --babelJest should generate proper jest.transform when babe
`; `;
exports[`jestProject --setup-file should have setupFilesAfterEnv and globals.ts-jest in the jest.config when generated for angular 1`] = ` exports[`jestProject --setup-file should have setupFilesAfterEnv and globals.ts-jest in the jest.config when generated for angular 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'lib1', displayName: 'lib1',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: { globals: {
'ts-jest': { 'ts-jest': {
@ -65,9 +69,10 @@ exports[`jestProject --setup-file should have setupFilesAfterEnv and globals.ts-
`; `;
exports[`jestProject should create a jest.config.ts 1`] = ` exports[`jestProject should create a jest.config.ts 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'lib1', displayName: 'lib1',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -78,6 +83,32 @@ exports[`jestProject should create a jest.config.ts 1`] = `
" "
`; `;
exports[`jestProject should generate files 1`] = `
"/* eslint-disable */
export default {
displayName: 'lib1',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\\\\\.(html|svg)$',
}
},
coverageDirectory: '../../coverage/libs/lib1',
transform: {
'^.+\\\\\\\\.(ts|mjs|js|html)$': 'jest-preset-angular'
},
transformIgnorePatterns: ['node_modules/(?!.*\\\\\\\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
]
};
"
`;
exports[`jestProject should use jest.config.js in project config with --js flag 1`] = ` exports[`jestProject should use jest.config.js in project config with --js flag 1`] = `
Object { Object {
"executor": "@nrwl/jest:jest", "executor": "@nrwl/jest:jest",

View File

@ -1,6 +1,7 @@
module.exports = { /* eslint-disable */
<% if(js){ %>module.exports =<% } else{ %>export default<% } %> {
displayName: '<%= project %>', displayName: '<%= project %>',
preset: '<%= offsetFromRoot %>jest.preset.ts', preset: '<%= offsetFromRoot %>jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: { globals: {
'ts-jest': { 'ts-jest': {

View File

@ -1,6 +1,7 @@
module.exports = { /* eslint-disable */
<% if(js){ %>module.exports =<% } else{ %>export default<% } %> {
displayName: '<%= project %>', displayName: '<%= project %>',
preset: '<%= offsetFromRoot %>jest.preset<%= ext %>',<% if(setupFile !== 'none') { %> preset: '<%= offsetFromRoot %>jest.preset.js',<% if(setupFile !== 'none') { %>
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],<% } %><% if (transformer === 'ts-jest') { %> setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],<% } %><% if (transformer === 'ts-jest') { %>
globals: { globals: {
'ts-jest': { 'ts-jest': {

View File

@ -53,6 +53,7 @@ describe('jestProject', () => {
expect(tree.exists('libs/lib1/src/test-setup.ts')).toBeTruthy(); expect(tree.exists('libs/lib1/src/test-setup.ts')).toBeTruthy();
expect(tree.exists('libs/lib1/jest.config.ts')).toBeTruthy(); expect(tree.exists('libs/lib1/jest.config.ts')).toBeTruthy();
expect(tree.exists('libs/lib1/tsconfig.spec.json')).toBeTruthy(); expect(tree.exists('libs/lib1/tsconfig.spec.json')).toBeTruthy();
expect(tree.read('libs/lib1/jest.config.ts', 'utf-8')).toMatchSnapshot();
}); });
it('should generate files w/babel-jest', async () => { it('should generate files w/babel-jest', async () => {
@ -284,7 +285,7 @@ describe('jestProject', () => {
).toMatchSnapshot(); ).toMatchSnapshot();
}); });
it('should use the jest.preset.ts when preset with --js', async () => { it('should always use jest.preset.js with --js', async () => {
tree.write('jest.preset.ts', ''); tree.write('jest.preset.ts', '');
await jestProjectGenerator(tree, { await jestProjectGenerator(tree, {
...defaultOptions, ...defaultOptions,
@ -293,7 +294,19 @@ describe('jestProject', () => {
} as JestProjectSchema); } as JestProjectSchema);
expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy(); expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy();
expect(tree.read('libs/lib1/jest.config.js', 'utf-8')).toContain( expect(tree.read('libs/lib1/jest.config.js', 'utf-8')).toContain(
"preset: '../../jest.preset.ts'," "preset: '../../jest.preset.js',"
);
});
it('should use module.exports with --js flag', async () => {
await jestProjectGenerator(tree, {
...defaultOptions,
project: 'lib1',
js: true,
} as JestProjectSchema);
expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy();
expect(tree.read('libs/lib1/jest.config.js', 'utf-8')).toContain(
'module.exports = {'
); );
}); });

View File

@ -4,7 +4,6 @@ import {
readProjectConfiguration, readProjectConfiguration,
Tree, Tree,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { findRootJestPreset } from '../../../utils/config/find-root-jest-files';
import { join } from 'path'; import { join } from 'path';
import { JestProjectSchema } from '../schema'; import { JestProjectSchema } from '../schema';
@ -27,7 +26,7 @@ export function createFiles(tree: Tree, options: JestProjectSchema) {
tmpl: '', tmpl: '',
...options, ...options,
transformer, transformer,
ext: findRootJestPreset(tree) === 'jest.preset.js' ? '.js' : '.ts', js: !!options.js,
projectRoot: projectConfig.root, projectRoot: projectConfig.root,
offsetFromRoot: offsetFromRoot(projectConfig.root), offsetFromRoot: offsetFromRoot(projectConfig.root),
}); });

View File

@ -1,9 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Jest Migration (v14.0.0) should NOT update jest.config.ts preset 1`] = `
"/* eslint-disable */
module.exports = {
displayName: 'lib-one',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
}
},
transform: {
'^.+\\\\\\\\.[tj]sx?$': 'ts-jest'
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/lib-one'
};
"
`;
exports[`Jest Migration (v14.0.0) should rename project jest.config.js to jest.config.ts 1`] = ` exports[`Jest Migration (v14.0.0) should rename project jest.config.js to jest.config.ts 1`] = `
"module.exports = { "/* eslint-disable */
displayName: 'lib-one',
module.exports = {
displayName: 'lib-one',
preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -13,25 +35,24 @@ exports[`Jest Migration (v14.0.0) should rename project jest.config.js to jest.c
'^.+\\\\\\\\.[tj]sx?$': 'ts-jest' '^.+\\\\\\\\.[tj]sx?$': 'ts-jest'
}, },
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/lib-one',\\"preset\\": \\"../../jest.preset.ts\\" coverageDirectory: '../../coverage/libs/lib-one'
}; };
" "
`; `;
exports[`Jest Migration (v14.0.0) should update jest.config.ts preset to use the jest.preset.ts 1`] = ` exports[`Jest Migration (v14.0.0) should update the excludes of next js apps using the project parser settings 1`] = `
"module.exports = { Object {
displayName: 'lib-one', "files": Array [
"*.ts",
globals: { "*.tsx",
'ts-jest': { "*.js",
tsconfig: '<rootDir>/tsconfig.spec.json', "*.jsx",
} ],
"parserOptions": Object {
"project": Array [
"libs/lib-one/tsconfig.*?.json",
],
}, },
transform: { "rules": Object {},
'^.+\\\\\\\\.[tj]sx?$': 'ts-jest' }
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/lib-one',\\"preset\\": \\"../../jest.preset.ts\\"
};
"
`; `;

View File

@ -7,48 +7,80 @@ import {
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { jestInitGenerator } from '@nrwl/jest'; import { jestInitGenerator } from '@nrwl/jest';
import { updateJestConfigExt } from './update-jest-config-ext';
import { libraryGenerator as workspaceLib } from '@nrwl/workspace'; import { libraryGenerator as workspaceLib } from '@nrwl/workspace';
import { updateJestConfigExt } from './update-jest-config-ext';
const setupDefaults = {
js: true,
skipPackageJson: true,
libName: 'lib-one',
setParserOptionsProject: false,
};
async function libSetUp(tree: Tree, options = setupDefaults) {
jestInitGenerator(tree, {
js: options.js,
skipPackageJson: options.skipPackageJson,
});
await workspaceLib(tree, {
name: options.libName,
setParserOptionsProject: options.setParserOptionsProject,
});
tree.rename(
`libs/${options.libName}/jest.config.ts`,
`libs/${options.libName}/jest.config.js`
);
const config = tree.read(`libs/${options.libName}/jest.config.js`, 'utf-8');
tree.write(
`libs/${options.libName}/jest.config.js`,
config
.replace(/\/\* eslint-disable \*\//g, '')
.replace(/export default/g, 'module.exports =')
);
updateProjectConfiguration(tree, options.libName, {
...readProjectConfiguration(tree, options.libName),
targets: {
test: {
executor: '@nrwl/jest:jest',
options: {
jestConfig: `libs/${options.libName}/jest.config.js`,
passWithNoTests: true,
},
configurations: {
production: {
silent: true,
},
},
},
},
});
}
describe('Jest Migration (v14.0.0)', () => { describe('Jest Migration (v14.0.0)', () => {
let tree: Tree; let tree: Tree;
beforeEach(async () => { beforeEach(async () => {
tree = createTreeWithEmptyWorkspace(2); tree = createTreeWithEmptyWorkspace(2);
jestInitGenerator(tree, { js: true, skipPackageJson: true });
await workspaceLib(tree, { name: 'lib-one' });
tree.rename('libs/lib-one/jest.config.ts', 'libs/lib-one/jest.config.js');
updateProjectConfiguration(tree, 'lib-one', {
...readProjectConfiguration(tree, 'lib-one'),
targets: {
test: {
executor: '@nrwl/jest:jest',
options: {
jestConfig: 'libs/lib-one/jest.config.js',
passWithNoTests: true,
},
configurations: {
production: {
silent: true,
},
},
},
},
});
}); });
it('should rename project jest.config.js to jest.config.ts', async () => { it('should rename project jest.config.js to jest.config.ts', async () => {
await libSetUp(tree);
await updateJestConfigExt(tree); await updateJestConfigExt(tree);
expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy(); expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy();
expect(tree.read('libs/lib-one/jest.config.ts', 'utf-8')).toMatchSnapshot(); expect(tree.read('libs/lib-one/jest.config.ts', 'utf-8')).toMatchSnapshot();
}); });
it('should rename root jest files', async () => { it('should rename root jest.config.js', async () => {
await libSetUp(tree);
await updateJestConfigExt(tree); await updateJestConfigExt(tree);
expect(tree.exists('jest.config.ts')).toBeTruthy(); expect(tree.exists('jest.config.ts')).toBeTruthy();
expect(tree.exists('jest.preset.ts')).toBeTruthy(); expect(tree.exists('jest.preset.js')).toBeTruthy();
}); });
it('should update jest.config.ts preset to use the jest.preset.ts', async () => { it('should NOT update jest.config.ts preset', async () => {
await libSetUp(tree);
tree.rename('libs/lib-one/jest.config.js', 'libs/lib-one/jest.config.ts'); tree.rename('libs/lib-one/jest.config.js', 'libs/lib-one/jest.config.ts');
const projectConfig = readProjectConfiguration(tree, 'lib-one'); const projectConfig = readProjectConfiguration(tree, 'lib-one');
updateProjectConfiguration(tree, 'lib-one', { updateProjectConfiguration(tree, 'lib-one', {
@ -70,6 +102,8 @@ describe('Jest Migration (v14.0.0)', () => {
}); });
it('should only update js/ts files', async () => { it('should only update js/ts files', async () => {
await libSetUp(tree);
tree.rename('libs/lib-one/jest.config.js', 'libs/lib-one/jest.config.ts'); tree.rename('libs/lib-one/jest.config.js', 'libs/lib-one/jest.config.ts');
updateProjectConfiguration(tree, 'lib-one', { updateProjectConfiguration(tree, 'lib-one', {
...readProjectConfiguration(tree, 'lib-one'), ...readProjectConfiguration(tree, 'lib-one'),
@ -84,7 +118,7 @@ describe('Jest Migration (v14.0.0)', () => {
}, },
}); });
await workspaceLib(tree, { name: 'lib-two' }); await libSetUp(tree, { ...setupDefaults, libName: 'lib-two' });
tree.delete('libs/lib-two/jest.config.ts'); // lib generator creates a ts file tree.delete('libs/lib-two/jest.config.ts'); // lib generator creates a ts file
tree.write('libs/lib-two/jest.config.json', '{}'); tree.write('libs/lib-two/jest.config.json', '{}');
updateProjectConfiguration(tree, 'lib-two', { updateProjectConfiguration(tree, 'lib-two', {
@ -99,8 +133,8 @@ describe('Jest Migration (v14.0.0)', () => {
}, },
}, },
}); });
await workspaceLib(tree, { name: 'lib-three' });
await libSetUp(tree, { ...setupDefaults, libName: 'lib-three' });
expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy(); expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy();
await updateJestConfigExt(tree); await updateJestConfigExt(tree);
expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy(); expect(tree.exists('libs/lib-one/jest.config.ts')).toBeTruthy();
@ -110,6 +144,8 @@ describe('Jest Migration (v14.0.0)', () => {
}); });
it('should not throw error if file does not exit', async () => { it('should not throw error if file does not exit', async () => {
await libSetUp(tree);
tree.delete('libs/lib-one/jest.config.js'); tree.delete('libs/lib-one/jest.config.js');
await updateJestConfigExt(tree); await updateJestConfigExt(tree);
expect(tree.exists('libs/lib-one/jest.config.ts')).toBeFalsy(); expect(tree.exists('libs/lib-one/jest.config.ts')).toBeFalsy();
@ -117,6 +153,8 @@ describe('Jest Migration (v14.0.0)', () => {
}); });
it('should update correct tsconfigs', async () => { it('should update correct tsconfigs', async () => {
await libSetUp(tree);
updateJson(tree, 'libs/lib-one/tsconfig.lib.json', (json) => { updateJson(tree, 'libs/lib-one/tsconfig.lib.json', (json) => {
json.exclude = ['**/*.spec.ts']; json.exclude = ['**/*.spec.ts'];
return json; return json;
@ -140,6 +178,8 @@ describe('Jest Migration (v14.0.0)', () => {
}); });
it('should add exclude to root tsconfig with no references', async () => { it('should add exclude to root tsconfig with no references', async () => {
await libSetUp(tree);
tree.delete('libs/lib-one/tsconfig.spec.json'); tree.delete('libs/lib-one/tsconfig.spec.json');
tree.delete('libs/lib-one/tsconfig.lib.json'); tree.delete('libs/lib-one/tsconfig.lib.json');
@ -156,4 +196,28 @@ describe('Jest Migration (v14.0.0)', () => {
expect(tree.exists('libs/lib-one/tsconfig.spec.json')).toBeFalsy(); expect(tree.exists('libs/lib-one/tsconfig.spec.json')).toBeFalsy();
expect(tree.exists('libs/lib-one/tsconfig.lib.json')).toBeFalsy(); expect(tree.exists('libs/lib-one/tsconfig.lib.json')).toBeFalsy();
}); });
it('should update the excludes of next js apps using the project parser settings', async () => {
await libSetUp(tree, { ...setupDefaults, setParserOptionsProject: true });
const projectConfig = readProjectConfiguration(tree, 'lib-one');
projectConfig.targets['build'] = {
executor: '@nrwl/next:build',
options: {},
};
updateProjectConfiguration(tree, 'lib-one', projectConfig);
updateJson(tree, 'libs/lib-one/tsconfig.json', (json) => {
// simulate nextJS tsconfig;
json.exclude = ['node_modules'];
return json;
});
const esLintJson = readJson(tree, 'libs/lib-one/.eslintrc.json');
// make sure the parserOptions are set correctly
expect(esLintJson.overrides[0]).toMatchSnapshot();
await updateJestConfigExt(tree);
const tsconfigSpec = readJson(tree, 'libs/lib-one/tsconfig.spec.json');
expect(tsconfigSpec.exclude).toEqual(['node_modules']);
});
}); });

View File

@ -2,7 +2,6 @@ import {
formatFiles, formatFiles,
joinPathFragments, joinPathFragments,
logger, logger,
offsetFromRoot,
ProjectConfiguration, ProjectConfiguration,
readJson, readJson,
readProjectConfiguration, readProjectConfiguration,
@ -11,43 +10,11 @@ import {
updateJson, updateJson,
updateProjectConfiguration, updateProjectConfiguration,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { jestConfigObject } from '../../utils/config/functions'; import { extname } from 'path';
import { dirname, extname, join } from 'path';
import {
removePropertyFromJestConfig,
addPropertyToJestConfig,
} from '../../utils/config/update-config';
import { JestExecutorOptions } from '../../executors/jest/schema'; import { JestExecutorOptions } from '../../executors/jest/schema';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
const allowedExt = ['.ts', '.js']; const allowedExt = ['.ts', '.js'];
let isRootPresetUpdated = false;
function updateJestPreset(
tree: Tree,
options: JestExecutorOptions,
projectName: string
) {
const oldConfig = jestConfigObject(tree, options.jestConfig);
if (!oldConfig) {
return;
}
// if using the root preset and the root preset was updated to ts file.
// then update the jest config
if (isRootPresetUpdated && oldConfig?.preset?.endsWith('jest.preset.js')) {
removePropertyFromJestConfig(tree, options.jestConfig, 'preset');
addPropertyToJestConfig(
tree,
options.jestConfig,
'preset',
joinPathFragments(
offsetFromRoot(dirname(options.jestConfig)),
'jest.preset.ts'
),
{ valueAsString: false }
);
}
}
function updateTsConfig(tree: Tree, tsConfigPath: string) { function updateTsConfig(tree: Tree, tsConfigPath: string) {
try { try {
@ -64,6 +31,17 @@ function updateTsConfig(tree: Tree, tsConfigPath: string) {
} }
} }
function addEsLintIgnoreComments(tree: Tree, filePath: string) {
if (tree.exists(filePath)) {
const contents = tree.read(filePath, 'utf-8');
tree.write(
filePath,
`/* eslint-disable */
${contents}`
);
}
}
function isJestConfigValid(tree: Tree, options: JestExecutorOptions) { function isJestConfigValid(tree: Tree, options: JestExecutorOptions) {
const configExt = extname(options.jestConfig); const configExt = extname(options.jestConfig);
@ -81,26 +59,49 @@ function isJestConfigValid(tree: Tree, options: JestExecutorOptions) {
function updateTsconfigSpec( function updateTsconfigSpec(
tree: Tree, tree: Tree,
projectConfig: ProjectConfiguration, projectConfig: ProjectConfiguration,
path path,
options: { isNextWithProjectParse: boolean; tsConfigPath: string } = {
isNextWithProjectParse: false,
tsConfigPath: '',
}
) { ) {
updateJson(tree, joinPathFragments(projectConfig.root, path), (json) => { updateJson(tree, joinPathFragments(projectConfig.root, path), (json) => {
json.include = Array.from( json.include = Array.from(
new Set([...(json.include || []), 'jest.config.ts']) new Set([...(json.include || []), 'jest.config.ts'])
); );
if (options.isNextWithProjectParse) {
const tsConfig = readJson(tree, options.tsConfigPath);
const tsConfigExclude = (tsConfig.exclude || []).filter(
(e) => e !== 'jest.config.ts'
);
json.exclude = Array.from(
new Set([...(json.exclude || []), ...tsConfigExclude])
);
}
return json; return json;
}); });
} }
function isNextWithProjectLint(
projectConfig: ProjectConfiguration,
esLintJson: any
) {
const esLintOverrides = esLintJson?.overrides?.find((o) =>
['*.ts', '*.tsx', '*.js', '*.jsx'].every((ext) => o.files.includes(ext))
);
// check if it's a next app and has a parserOptions.project set in the eslint overrides
return !!(
projectConfig?.targets?.['build']?.executor === '@nrwl/next:build' &&
esLintOverrides?.parserOptions?.project
);
}
export async function updateJestConfigExt(tree: Tree) { export async function updateJestConfigExt(tree: Tree) {
if (tree.exists('jest.config.js')) { if (tree.exists('jest.config.js')) {
tree.rename('jest.config.js', 'jest.config.ts'); tree.rename('jest.config.js', 'jest.config.ts');
} }
if (tree.exists('jest.preset.js')) {
isRootPresetUpdated = true;
tree.rename('jest.preset.js', 'jest.preset.ts');
}
forEachExecutorOptions<JestExecutorOptions>( forEachExecutorOptions<JestExecutorOptions>(
tree, tree,
'@nrwl/jest:jest', '@nrwl/jest:jest',
@ -111,7 +112,7 @@ export async function updateJestConfigExt(tree: Tree) {
return; return;
} }
updateJestPreset(tree, options, projectName); addEsLintIgnoreComments(tree, options.jestConfig);
const newJestConfigPath = options.jestConfig.replace('.js', '.ts'); const newJestConfigPath = options.jestConfig.replace('.js', '.ts');
tree.rename(options.jestConfig, newJestConfigPath); tree.rename(options.jestConfig, newJestConfigPath);
@ -125,7 +126,19 @@ export async function updateJestConfigExt(tree: Tree) {
if (tsConfig.references) { if (tsConfig.references) {
for (const { path } of tsConfig.references) { for (const { path } of tsConfig.references) {
if (path.endsWith('tsconfig.spec.json')) { if (path.endsWith('tsconfig.spec.json')) {
updateTsconfigSpec(tree, projectConfig, path); const eslintPath = joinPathFragments(
projectConfig.root,
'.eslintrc.json'
);
updateTsconfigSpec(tree, projectConfig, path, {
isNextWithProjectParse: tree.exists(eslintPath)
? isNextWithProjectLint(
projectConfig,
readJson(tree, eslintPath)
)
: false,
tsConfigPath: filePath,
});
continue; continue;
} }

View File

@ -0,0 +1,76 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Jest Migration (v14.1.2) should convert module.exports => export default 1`] = `
"const { getJestProjects } = require('@nrwl/jest');
const nxPreset = require('@nrwl/jest/preset');
const someFn = () => ({more: 'stuff'});
module.export.abc = someFn;
export default {
...nxPreset,
more: 'stuff',
someFn,
projects: getJestProjects()
};"
`;
exports[`Jest Migration (v14.1.2) should update individual project jest configs 1`] = `
"
const nxPreset = require('@nrwl/jest/preset').default;
const someOtherImport = require('../something/else.js');
export default {
...someOtherImport,
...nxPreset,
displayName: 'lib-one',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\\\\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/apps/lib-one',
transform: {
'^.+\\\\\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\\\\\\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
"
`;
exports[`Jest Migration (v14.1.2) should work with multiple configurations 1`] = `
"
const nxPreset = require('@nrwl/jest/preset').default;
const someOtherImport = require('../something/else.js');
export default {
...someOtherImport,
...nxPreset,
displayName: 'lib-one',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\\\\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/apps/lib-one',
transform: {
'^.+\\\\\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\\\\\\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
"
`;

View File

@ -0,0 +1,178 @@
import {
readProjectConfiguration,
stripIndents,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { createTree, createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { libraryGenerator as workspaceLib } from '@nrwl/workspace';
import {
updateExportsJestConfig,
updateRootFiles,
updateToDefaultExport,
} from './update-exports-jest-config';
describe('Jest Migration (v14.1.2)', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace(2);
});
it('should update root jest files', () => {
tree.write(
'jest.config.ts',
stripIndents`
const { getJestProjects } = require('@nrwl/jest');
module.exports = {
projects: getJestProjects()
};`
);
tree.write(
'jest.preset.ts',
stripIndents`
const nxPreset = require('@nrwl/jest/preset');
module.exports = { ...nxPreset };`
);
const status = updateRootFiles(tree);
expect(status).toEqual({ didUpdateRootPreset: true });
expect(tree.read('jest.config.ts', 'utf-8')).toEqual(stripIndents`
const { getJestProjects } = require('@nrwl/jest');
export default {
projects: getJestProjects()
};
`);
expect(tree.read('jest.preset.js', 'utf-8')).toEqual(stripIndents`
const nxPreset = require('@nrwl/jest/preset').default;
module.exports = { ...nxPreset };`);
});
it('should update individual project jest configs', async () => {
await workspaceLib(tree, { name: 'lib-one' });
tree.rename('jest.preset.js', 'jest.preset.ts');
tree.write(
'libs/lib-one/jest.config.ts',
`
const nxPreset = require('@nrwl/jest/preset');
const someOtherImport = require('../something/else.js');
module.exports = {
...someOtherImport,
...nxPreset,
displayName: 'lib-one',
preset: '../../jest.preset.ts',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/apps/lib-one',
transform: {
'^.+\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
`
);
updateExportsJestConfig(tree);
const config = tree.read('libs/lib-one/jest.config.ts', 'utf-8');
expect(config).toMatchSnapshot();
});
it('should work with multiple configurations', async () => {
await workspaceLib(tree, { name: 'lib-one' });
tree.rename('jest.preset.js', 'jest.preset.ts');
updateProjectConfiguration(tree, 'lib-one', {
...readProjectConfiguration(tree, 'lib-one'),
targets: {
test: {
executor: '@nrwl/jest:jest',
options: {
jestConfig: 'libs/lib-one/jest.config.ts',
passWithoutTests: true,
},
configurations: {
production: {
silent: true,
},
},
},
},
});
tree.write(
'libs/lib-one/jest.config.ts',
`
const nxPreset = require('@nrwl/jest/preset');
const someOtherImport = require('../something/else.js');
module.exports = {
...someOtherImport,
...nxPreset,
displayName: 'lib-one',
preset: '../../jest.preset.ts',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/apps/lib-one',
transform: {
'^.+\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
`
);
updateExportsJestConfig(tree);
const config = tree.read('libs/lib-one/jest.config.ts', 'utf-8');
expect(config).toMatchSnapshot();
expect(tree.exists('jest.preset.ts')).toBeFalsy();
expect(tree.exists('jest.preset.js')).toBeTruthy();
});
it('should convert module.exports => export default', () => {
tree = createTree();
tree.write(
'jest.config.js',
stripIndents`
const { getJestProjects } = require('@nrwl/jest');
const nxPreset = require('@nrwl/jest/preset');
const someFn = () => ({more: 'stuff'});
module.export.abc = someFn;
module.exports = {
...nxPreset,
more: 'stuff',
someFn,
projects: getJestProjects()
};`
);
updateToDefaultExport(tree, 'jest.config.js');
expect(tree.read('jest.config.js', 'utf-8')).toMatchSnapshot();
});
});

View File

@ -0,0 +1,85 @@
import type { Tree } from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { tsquery } from '@phenomnomnominal/tsquery';
import type { BinaryExpression } from 'typescript';
import type { JestExecutorOptions } from '../../executors/jest/schema';
export function updateExportsJestConfig(tree: Tree) {
const { didUpdateRootPreset } = updateRootFiles(tree);
forEachExecutorOptions<JestExecutorOptions>(
tree,
'@nrwl/jest:jest',
(options) => {
if (options.jestConfig && tree.exists(options.jestConfig)) {
if (options.jestConfig.endsWith('.ts')) {
updateToDefaultExport(tree, options.jestConfig);
}
const updatedImport = updateNxPresetImport(
tree.read(options.jestConfig, 'utf-8')
);
tree.write(options.jestConfig, updatedImport);
// jest.preset.ts => jest.preset.js
if (didUpdateRootPreset) {
const projectConfig = tree.read(options.jestConfig, 'utf-8');
const updatedConfig = projectConfig.replace(
/(preset:\s*['"][.\/]*)(jest\.preset\.ts)(['"])/g,
'$1jest.preset.js$3'
);
tree.write(options.jestConfig, updatedConfig);
}
}
}
);
}
export function updateRootFiles(tree: Tree): { didUpdateRootPreset: boolean } {
let didUpdateRootPreset = false;
if (tree.exists('jest.config.ts')) {
updateToDefaultExport(tree, 'jest.config.ts');
}
if (tree.exists('jest.preset.ts')) {
// fix those who ran v14 migration where this was renamed.
tree.rename('jest.preset.ts', 'jest.preset.js');
didUpdateRootPreset = true;
}
if (tree.exists('jest.preset.js')) {
const newContents = updateNxPresetImport(
tree.read('jest.preset.js', 'utf-8')
);
tree.write('jest.preset.js', newContents);
}
return {
didUpdateRootPreset,
};
}
function updateNxPresetImport(fileContents: string): string {
return fileContents.replace(
/require\(['"]@nrwl\/jest\/preset['"]\)[;\s]*?[\n\r]/g,
`require('@nrwl/jest/preset').default;
`
);
}
export function updateToDefaultExport(tree: Tree, filePath: string) {
const newConfig = tsquery.replace(
tree.read(filePath, 'utf-8'),
'ExpressionStatement BinaryExpression',
(node: BinaryExpression) => {
if (node.left.getText() === 'module.exports') {
return `export default ${node.right.getText()}`;
}
return node.getText();
}
);
tree.write(filePath, newConfig);
}
export default updateExportsJestConfig;

View File

@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`jestConfigObject export default should handle spread assignments 1`] = `
"{
...nxPreset,
abc: 'xyz'
}"
`;
exports[`jestConfigObject export default should work for basic cases 1`] = `
"{
abc: 'xyz'
}"
`;

View File

@ -17,9 +17,5 @@ export function findRootJestPreset(tree: Tree): string | null {
return 'jest.preset.js'; return 'jest.preset.js';
} }
if (tree.exists('jest.preset.ts')) {
return 'jest.preset.ts';
}
return null; return null;
} }

View File

@ -1,70 +1,72 @@
import { createTree } from '@nrwl/devkit/testing'; import { createTree } from '@nrwl/devkit/testing';
import { jestConfigObject } from './functions'; import { jestConfigObject, jestConfigObjectAst } from './functions';
describe('jestConfigObject', () => { describe('jestConfigObject', () => {
it('should work for basic cases', () => { describe('module.exports', () => {
const tree = createTree(); it('should work for basic cases', () => {
tree.write( const tree = createTree();
'jest.config.js', tree.write(
` 'jest.config.js',
`
module.exports = { module.exports = {
foo: 'bar' foo: 'bar'
}; };
` `
); );
expect(jestConfigObject(tree, 'jest.config.js')).toEqual({ expect(jestConfigObject(tree, 'jest.config.js')).toEqual({
foo: 'bar', foo: 'bar',
});
}); });
});
xit('should work with async functions', async () => { xit('should work with async functions', async () => {
const tree = createTree(); const tree = createTree();
jest.mock('@nrwl/jest', () => ({ jest.mock('@nrwl/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'], getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
})); }));
tree.write( tree.write(
'jest.config.js', 'jest.config.js',
` `
const { getJestProjects } = require('@nrwl/jest'); const { getJestProjects } = require('@nrwl/jest');
module.exports = async () => ({ module.exports = async () => ({
foo: 'bar' foo: 'bar'
}); });
` `
); );
expect(await jestConfigObject(tree, 'jest.config.js')).toEqual({ expect(await jestConfigObject(tree, 'jest.config.js')).toEqual({
foo: 'bar', foo: 'bar',
});
}); });
});
it('should work with `getJestConfig`', () => { it('should work with `getJestConfig`', () => {
const tree = createTree(); const tree = createTree();
jest.mock('@nrwl/jest', () => ({ jest.mock('@nrwl/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'], getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
})); }));
tree.write( tree.write(
'jest.config.js', 'jest.config.js',
` `
const { getJestProjects } = require('@nrwl/jest'); const { getJestProjects } = require('@nrwl/jest');
module.exports = { module.exports = {
projects: getJestProjects() projects: getJestProjects()
}; };
` `
); );
expect(jestConfigObject(tree, 'jest.config.js')).toEqual({ expect(jestConfigObject(tree, 'jest.config.js')).toEqual({
projects: ['<rootDir>/project-a', '<rootDir>/project-b'], projects: ['<rootDir>/project-a', '<rootDir>/project-b'],
});
}); });
});
it('should work with node globals (require, __dirname, process, __filename, console, and other globals)', () => { it('should work with node globals (require, __dirname, process, __filename, console, and other globals)', () => {
const tree = createTree(); const tree = createTree();
jest.mock('@nrwl/jest', () => ({ jest.mock('@nrwl/jest', () => ({
getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'], getJestProjects: () => ['<rootDir>/project-a', '<rootDir>/project-b'],
})); }));
tree.write( tree.write(
'jest.config.js', 'jest.config.js',
` `
const { getJestProjects } = require('@nrwl/jest'); const { getJestProjects } = require('@nrwl/jest');
module.exports = { module.exports = {
projects: getJestProjects(), projects: getJestProjects(),
@ -73,13 +75,37 @@ describe('jestConfigObject', () => {
dirname: __dirname dirname: __dirname
}; };
` `
); );
expect(jestConfigObject(tree, 'jest.config.js')).toEqual({ expect(jestConfigObject(tree, 'jest.config.js')).toEqual({
dirname: '/virtual', dirname: '/virtual',
filename: '/virtual/jest.config.js', filename: '/virtual/jest.config.js',
env: process.env, env: process.env,
projects: ['<rootDir>/project-a', '<rootDir>/project-b'], projects: ['<rootDir>/project-a', '<rootDir>/project-b'],
});
});
});
describe('export default', () => {
it('should work for basic cases', () => {
const content = `
export default {
abc: 'xyz'
}`;
expect(jestConfigObjectAst(content).getText()).toMatchSnapshot();
});
it('should handle spread assignments', () => {
const content = `
import { nxPreset } from '@nrwl/jest/preset';
export default {
...nxPreset,
abc: 'xyz'
}`;
expect(jestConfigObjectAst(content).getText()).toMatchSnapshot();
}); });
}); });
}); });

View File

@ -1,12 +1,4 @@
import * as ts from 'typescript'; import * as ts from 'typescript';
import {
BinaryExpression,
ExpressionStatement,
isBinaryExpression,
isExpressionStatement,
isPropertyAssignment,
SyntaxKind,
} from 'typescript';
import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit';
import { Config } from '@jest/types'; import { Config } from '@jest/types';
import { createContext, runInContext } from 'vm'; import { createContext, runInContext } from 'vm';
@ -24,7 +16,7 @@ function findPropertyAssignment(
propertyName: string propertyName: string
) { ) {
return object.properties.find((prop) => { return object.properties.find((prop) => {
if (!isPropertyAssignment(prop)) { if (!ts.isPropertyAssignment(prop)) {
return false; return false;
} }
const propNameText = prop.name.getText(); const propNameText = prop.name.getText();
@ -171,11 +163,27 @@ export function removeProperty(
} }
} }
function isModuleExport(node: ts.Statement) {
return (
ts.isExpressionStatement(node) &&
node.expression?.kind &&
ts.isBinaryExpression(node.expression) &&
node.expression.left.getText() === 'module.exports' &&
node.expression.operatorToken?.kind === ts.SyntaxKind.EqualsToken
);
}
function isDefaultExport(node: ts.Statement) {
return (
ts.isExportAssignment(node) &&
node.expression?.kind &&
ts.isObjectLiteralExpression(node.expression) &&
node.getText().startsWith('export default')
);
}
/** /**
* Should be used to get the jest config object. * Should be used to get the jest config object as AST
*
* @param host
* @param path
*/ */
export function jestConfigObjectAst( export function jestConfigObjectAst(
fileContent: string fileContent: string
@ -187,32 +195,51 @@ export function jestConfigObjectAst(
true true
); );
const moduleExportsStatement = sourceFile.statements.find( const exportStatement = sourceFile.statements.find(
(statement) => (statement) => isModuleExport(statement) || isDefaultExport(statement)
isExpressionStatement(statement) &&
isBinaryExpression(statement.expression) &&
statement.expression.left.getText() === 'module.exports' &&
statement.expression.operatorToken.kind === SyntaxKind.EqualsToken
); );
const moduleExports = (moduleExportsStatement as ExpressionStatement) let ast: ts.ObjectLiteralExpression;
.expression as BinaryExpression; if (ts.isExpressionStatement(exportStatement)) {
const moduleExports = exportStatement.expression as ts.BinaryExpression;
if (!moduleExports) { if (!moduleExports) {
throw new Error( throw new Error(
` `
The provided jest config file does not have the expected 'module.exports' expression. The provided jest config file does not have the expected 'module.exports' expression.
See https://jestjs.io/docs/en/configuration for more details.` See https://jestjs.io/docs/en/configuration for more details.`
); );
} }
if (!ts.isObjectLiteralExpression(moduleExports.right)) { ast = moduleExports.right as ts.ObjectLiteralExpression;
} else if (ts.isExportAssignment(exportStatement)) {
const defaultExport =
exportStatement.expression as ts.ObjectLiteralExpression;
if (!defaultExport) {
throw new Error(
`
The provided jest config file does not have the expected 'export default' expression.
See https://jestjs.io/docs/en/configuration for more details.`
);
}
ast = defaultExport;
}
if (!ast) {
throw new Error( throw new Error(
`The 'module.exports' expression is not an object literal.` `
The provided jest config file does not have the expected 'module.exports' or 'export default' expression.
See https://jestjs.io/docs/en/configuration for more details.`
); );
} }
return moduleExports.right as ts.ObjectLiteralExpression; if (!ts.isObjectLiteralExpression(ast)) {
throw new Error(
`The 'export default' or 'module.exports' expression is not an object literal.`
);
}
return ast;
} }
/** /**
@ -228,10 +255,18 @@ export function jestConfigObject(
const contents = host.read(path, 'utf-8'); const contents = host.read(path, 'utf-8');
let module = { exports: {} }; let module = { exports: {} };
// transform the export default syntax to module.exports
// this will work for the default config, but will break if there are any other ts syntax
// TODO(caleb): use the AST to transform back to the module.exports syntax so this will keep working
// or deprecate and make a new method for getting the jest config object
const forcedModuleSyntax = contents.replace(
/export\s+default/,
'module.exports ='
);
// Run the contents of the file with some stuff from this current context // Run the contents of the file with some stuff from this current context
// The module.exports will be mutated by the contents of the file... // The module.exports will be mutated by the contents of the file...
runInContext( runInContext(
contents, forcedModuleSyntax,
createContext({ createContext({
module, module,
require, require,

View File

@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`lib --unit-test-runner jest should generate test configuration with swc and js 1`] = `
"/* eslint-disable */
const { readFileSync } = require('fs')
// Reading the SWC compilation config and remove the \\"exclude\\"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(\`\${__dirname}/.lib.swcrc\`, 'utf-8')
);
module.exports = {
displayName: 'my-lib',
preset: '../../jest.preset.js',
transform: {
'^.+\\\\\\\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/libs/my-lib'
};
"
`;

View File

@ -1,14 +1,14 @@
import { readFileSync } from 'fs'; /* eslint-disable */
<% if(js) {%>const { readFileSync } = require('fs')<% } else { %>import { readFileSync } from 'fs';<% } %>
// Reading the SWC compilation config and remove the "exclude" // Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC // for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse( const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.lib.swcrc`, 'utf-8') readFileSync(`${__dirname}/.lib.swcrc`, 'utf-8')
); );
<% if(js) {%>module.exports =<% } else { %>export default<% } %> {
module.exports = {
displayName: '<%= project %>', displayName: '<%= project %>',
preset: '<%= offsetFromRoot %>jest.preset.<%= ext %>', preset: '<%= offsetFromRoot %>jest.preset.js',
transform: { transform: {
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig], '^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
}, },

View File

@ -698,9 +698,10 @@ describe('lib', () => {
expect(tree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy(); expect(tree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy();
expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8')) expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -718,6 +719,30 @@ describe('lib', () => {
expect(readme).toContain('nx test my-lib'); expect(readme).toContain('nx test my-lib');
}); });
it('should generate test configuration with swc and js', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
unitTestRunner: 'jest',
compiler: 'swc',
js: true,
});
expect(tree.exists('libs/my-lib/tsconfig.spec.json')).toBeTruthy();
expect(tree.exists('libs/my-lib/jest.config.js')).toBeTruthy();
expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
const projectConfig = readProjectConfiguration(tree, 'my-lib');
expect(projectConfig.targets.test).toBeDefined();
expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy();
expect(
tree.read(`libs/my-lib/jest.config.js`, 'utf-8')
).toMatchSnapshot();
const readme = tree.read('libs/my-lib/README.md', 'utf-8');
expect(readme).toContain('nx test my-lib');
});
describe('--buildable', () => { describe('--buildable', () => {
it('should generate the build target', async () => { it('should generate the build target', async () => {
await libraryGenerator(tree, { await libraryGenerator(tree, {

View File

@ -216,7 +216,6 @@ function addBabelRc(tree: Tree, options: NormalizedSchema) {
function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) { function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
const { className, name, propertyName } = names(options.name); const { className, name, propertyName } = names(options.name);
generateFiles(tree, filesDir, options.projectRoot, { generateFiles(tree, filesDir, options.projectRoot, {
...options, ...options,
dot: '.', dot: '.',
@ -290,10 +289,19 @@ function replaceJestConfig(
options: NormalizedSchema, options: NormalizedSchema,
filesDir: string filesDir: string
) { ) {
// the existing config has to be deleted otherwise the new config won't overwrite it
const existingJestConfig = joinPathFragments(
filesDir,
`jest.config.${options.js ? 'js' : 'ts'}`
);
if (tree.exists(existingJestConfig)) {
tree.delete(existingJestConfig);
}
// replace with JS:SWC specific jest config // replace with JS:SWC specific jest config
generateFiles(tree, filesDir, options.projectRoot, { generateFiles(tree, filesDir, options.projectRoot, {
tmpl: '', ext: options.js ? 'js' : 'ts',
ext: findRootJestPreset(tree) === 'jest.preset.js' ? 'js' : 'ts', js: !!options.js,
project: options.name, project: options.name,
offsetFromRoot: offsetFromRoot(options.projectRoot), offsetFromRoot: offsetFromRoot(options.projectRoot),
projectRoot: options.projectRoot, projectRoot: options.projectRoot,

View File

@ -83,9 +83,10 @@ exports[`@nrwl/linter:workspace-rules-project should generate the required files
`; `;
exports[`@nrwl/linter:workspace-rules-project should generate the required files 5`] = ` exports[`@nrwl/linter:workspace-rules-project should generate the required files 5`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'eslint-rules', displayName: 'eslint-rules',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',

View File

@ -1,9 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`lib --testEnvironment should set target jest testEnvironment to jsdom 1`] = ` exports[`lib --testEnvironment should set target jest testEnvironment to jsdom 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -19,9 +20,10 @@ exports[`lib --testEnvironment should set target jest testEnvironment to jsdom 1
`; `;
exports[`lib --testEnvironment should set target jest testEnvironment to node by default 1`] = ` exports[`lib --testEnvironment should set target jest testEnvironment to node by default 1`] = `
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',

View File

@ -40,6 +40,14 @@ export async function addJest(host: Tree, options: NormalizedSchema) {
joinPathFragments(options.appProjectRoot, 'tsconfig.spec.json'), joinPathFragments(options.appProjectRoot, 'tsconfig.spec.json'),
(json) => { (json) => {
json.compilerOptions.jsx = 'react'; json.compilerOptions.jsx = 'react';
// have to override exclude otherwise lint will fail with setParserOptionsProject and jest.config.ts
if (options.setParserOptionsProject) {
const tsConfig = readJson(
host,
joinPathFragments(options.appProjectRoot, 'tsconfig.json')
);
json.exclude = tsConfig.exclude.filter((e) => e !== 'jest.config.ts');
}
return json; return json;
} }
); );

View File

@ -374,9 +374,10 @@ describe('app', () => {
expect(tree.read(`apps/my-node-app/jest.config.ts`, 'utf-8')) expect(tree.read(`apps/my-node-app/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-node-app', displayName: 'my-node-app',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
testEnvironment: 'node', testEnvironment: 'node',
transform: { transform: {
'^.+\\\\\\\\.[tj]s$': 'babel-jest' '^.+\\\\\\\\.[tj]s$': 'babel-jest'

View File

@ -462,9 +462,10 @@ describe('lib', () => {
expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8')) expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
testEnvironment: 'node', testEnvironment: 'node',
transform: { transform: {
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest' '^.+\\\\\\\\.[tj]sx?$': 'babel-jest'

View File

@ -421,9 +421,10 @@ describe('app', () => {
expect(tree.read(`apps/my-app/jest.config.ts`, 'utf-8')) expect(tree.read(`apps/my-app/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-app', displayName: 'my-app',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
transform: { transform: {
'^.+\\\\\\\\.[tj]s$': 'babel-jest' '^.+\\\\\\\\.[tj]s$': 'babel-jest'
@ -443,9 +444,10 @@ describe('app', () => {
expect(tree.read(`apps/my-app/jest.config.ts`, 'utf-8')) expect(tree.read(`apps/my-app/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-app', displayName: 'my-app',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
transform: { transform: {
'^.+\\\\\\\\.[tj]s$': '@swc/jest' '^.+\\\\\\\\.[tj]s$': '@swc/jest'

View File

@ -195,9 +195,10 @@ describe('lib', () => {
expect(tree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy(); expect(tree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy();
expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8')) expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
globals: { globals: {
'ts-jest': { 'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json', tsconfig: '<rootDir>/tsconfig.spec.json',
@ -227,9 +228,9 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
}); });
const expectedRootJestConfig = ` const expectedRootJestConfig = `
"const { getJestProjects } = require('@nrwl/jest'); "import { getJestProjects } from '@nrwl/jest';
module.exports = { export default {
projects: getJestProjects() projects: getJestProjects()
};" };"
`; `;
@ -829,9 +830,10 @@ describe('lib', () => {
expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8')) expect(tree.read(`libs/my-lib/jest.config.ts`, 'utf-8'))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"module.exports = { "/* eslint-disable */
export default {
displayName: 'my-lib', displayName: 'my-lib',
preset: '../../jest.preset.ts', preset: '../../jest.preset.js',
transform: { transform: {
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest' '^.+\\\\\\\\.[tj]sx?$': 'babel-jest'
}, },

View File

@ -21,7 +21,7 @@ describe('move', () => {
const jestConfigPath = 'libs/shared/my-lib-new/jest.config.ts'; const jestConfigPath = 'libs/shared/my-lib-new/jest.config.ts';
const afterJestConfig = tree.read(jestConfigPath, 'utf-8'); const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
expect(tree.exists(jestConfigPath)).toBeTruthy(); expect(tree.exists(jestConfigPath)).toBeTruthy();
expect(afterJestConfig).toContain("preset: '../../../jest.preset.ts'"); expect(afterJestConfig).toContain("preset: '../../../jest.preset.js'");
expect(afterJestConfig).toContain( expect(afterJestConfig).toContain(
"coverageDirectory: '../../../coverage/libs/shared/my-lib-new'" "coverageDirectory: '../../../coverage/libs/shared/my-lib-new'"
); );
@ -39,7 +39,7 @@ describe('move', () => {
const jestConfigPath = 'libs/my-lib-new/jest.config.ts'; const jestConfigPath = 'libs/my-lib-new/jest.config.ts';
const afterJestConfig = tree.read(jestConfigPath, 'utf-8'); const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
expect(tree.exists(jestConfigPath)).toBeTruthy(); expect(tree.exists(jestConfigPath)).toBeTruthy();
expect(afterJestConfig).toContain("preset: '../../jest.preset.ts'"); expect(afterJestConfig).toContain("preset: '../../jest.preset.js'");
expect(afterJestConfig).toContain( expect(afterJestConfig).toContain(
"coverageDirectory: '../../coverage/libs/my-lib-new'" "coverageDirectory: '../../coverage/libs/my-lib-new'"
); );