Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(testing): handle existing jest preset file correctly #23437

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/jest/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { nxPreset } from './preset/jest-preset';

export { nxPreset };

export default nxPreset;
Original file line number Diff line number Diff line change
Expand Up @@ -262,19 +262,33 @@ describe('jestProject', () => {
expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy();
});

it('should always use jest.preset.js with --js', async () => {
tree.write('jest.preset.ts', '');
it('should generate a jest.preset.js when it does not exist', async () => {
await configurationGenerator(tree, {
...defaultOptions,
project: 'lib1',
js: true,
} as JestProjectSchema);
expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy();
expect(tree.exists('jest.preset.js')).toBeTruthy();
expect(tree.read('libs/lib1/jest.config.js', 'utf-8')).toContain(
"preset: '../../jest.preset.js',"
);
});

it('should not override existing jest preset file and should point to it in jest.config files', async () => {
tree.write('jest.preset.mjs', 'export default {}');
await configurationGenerator(tree, {
...defaultOptions,
project: 'lib1',
js: true,
} as JestProjectSchema);
expect(tree.exists('libs/lib1/jest.config.js')).toBeTruthy();
expect(tree.exists('jest.preset.mjs')).toBeTruthy();
expect(tree.read('libs/lib1/jest.config.js', 'utf-8')).toContain(
"preset: '../../jest.preset.mjs',"
);
});

it('should use module.exports with --js flag', async () => {
await configurationGenerator(tree, {
...defaultOptions,
Expand Down
4 changes: 2 additions & 2 deletions packages/jest/src/generators/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '@nx/devkit';
import { initGenerator as jsInitGenerator } from '@nx/js';
import { JestPluginOptions } from '../../plugins/plugin';
import { isPresetCjs } from '../../utils/config/is-preset-cjs';
import { getPresetExt } from '../../utils/config/config-file';

const schemaDefaults = {
setupFile: 'none',
Expand Down Expand Up @@ -90,7 +90,7 @@ export async function configurationGeneratorInternal(
tasks.push(ensureDependencies(tree, options));
}

const presetExt = isPresetCjs(tree) ? 'cjs' : 'js';
const presetExt = getPresetExt(tree);

await createJestConfig(tree, options, presetExt);
checkForTestTarget(tree, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ projects: await getJestProjectsAsync()
exports[`createJestConfig should generate files 2`] = `
"const nxPreset = require('@nx/jest/preset').default;

module.exports = { ...nxPreset }"
module.exports = { ...nxPreset };"
`;

exports[`createJestConfig should generate files with --js flag 1`] = `
Expand All @@ -25,5 +25,5 @@ projects: await getJestProjectsAsync()
exports[`createJestConfig should generate files with --js flag 2`] = `
"const nxPreset = require('@nx/jest/preset').default;

module.exports = { ...nxPreset }"
module.exports = { ...nxPreset };"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import {
Tree,
} from '@nx/devkit';
import { join } from 'path';
import type { JestPresetExtension } from '../../../utils/config/config-file';
import { NormalizedJestProjectSchema } from '../schema';

export function createFiles(
tree: Tree,
options: NormalizedJestProjectSchema,
presetExt: 'cjs' | 'js'
presetExt: JestPresetExtension
) {
const projectConfig = readProjectConfiguration(tree, options.project);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,34 @@ import {
type Tree,
} from '@nx/devkit';
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
import { findRootJestConfig } from '../../../utils/config/find-root-jest-files';
import {
findRootJestConfig,
type JestPresetExtension,
} from '../../../utils/config/config-file';
import type { NormalizedJestProjectSchema } from '../schema';

export async function createJestConfig(
tree: Tree,
options: Partial<NormalizedJestProjectSchema>,
presetExt: 'cjs' | 'js'
presetExt: JestPresetExtension
) {
if (!tree.exists(`jest.preset.${presetExt}`)) {
// preset is always js file.
tree.write(
`jest.preset.${presetExt}`,
`
const nxPreset = require('@nx/jest/preset').default;
if (presetExt === 'mjs') {
tree.write(
`jest.preset.${presetExt}`,
`import { nxPreset } from '@nx/jest/preset.js';

module.exports = { ...nxPreset }`
);
export default { ...nxPreset };`
);
} else {
// js or cjs
tree.write(
`jest.preset.${presetExt}`,
`const nxPreset = require('@nx/jest/preset').default;

module.exports = { ...nxPreset };`
);
}
}
if (options.rootProject) {
// we don't want any config to be made because the `configurationGenerator` will do it.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { findRootJestConfig } from '../../../utils/config/find-root-jest-files';
import { NormalizedJestProjectSchema } from '../schema';
import { readProjectConfiguration, type Tree } from '@nx/devkit';
import { findRootJestConfig } from '../../../utils/config/config-file';
import { addPropertyToJestConfig } from '../../../utils/config/update-config';
import { readProjectConfiguration, Tree } from '@nx/devkit';
import type { NormalizedJestProjectSchema } from '../schema';

function isUsingUtilityFunction(host: Tree) {
const rootConfig = findRootJestConfig(host);
Expand Down
21 changes: 12 additions & 9 deletions packages/jest/src/generators/init/init.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import {
addDependenciesToPackageJson,
createProjectGraphAsync,
formatFiles,
readNxJson,
removeDependenciesFromPackageJson,
runTasksInSerial,
updateNxJson,
type GeneratorCallback,
type Tree,
createProjectGraphAsync,
} from '@nx/devkit';
import { addPlugin } from '@nx/devkit/src/utils/add-plugin';
import { createNodes } from '../../plugins/plugin';
import {
getPresetExt,
type JestPresetExtension,
} from '../../utils/config/config-file';
import { jestVersion, nxVersion } from '../../utils/versions';
import { isPresetCjs } from '../../utils/config/is-preset-cjs';
import type { JestInitSchema } from './schema';
import { addPlugin } from '@nx/devkit/src/utils/add-plugin';

function updateProductionFileSet(tree: Tree, presetExt: 'cjs' | 'js') {
leosvelperez marked this conversation as resolved.
Show resolved Hide resolved
function updateProductionFileSet(tree: Tree) {
const nxJson = readNxJson(tree);

const productionFileSet = nxJson.namedInputs?.production;
Expand All @@ -40,7 +43,7 @@ function updateProductionFileSet(tree: Tree, presetExt: 'cjs' | 'js') {
updateNxJson(tree, nxJson);
}

function addJestTargetDefaults(tree: Tree, presetEnv: 'cjs' | 'js') {
function addJestTargetDefaults(tree: Tree, presetExt: JestPresetExtension) {
const nxJson = readNxJson(tree);

nxJson.targetDefaults ??= {};
Expand All @@ -53,7 +56,7 @@ function addJestTargetDefaults(tree: Tree, presetEnv: 'cjs' | 'js') {
nxJson.targetDefaults['@nx/jest:jest'].inputs ??= [
'default',
productionFileSet ? '^production' : '^default',
`{workspaceRoot}/jest.preset.${presetEnv}`,
`{workspaceRoot}/jest.preset.${presetExt}`,
];

nxJson.targetDefaults['@nx/jest:jest'].options ??= {
Expand Down Expand Up @@ -96,10 +99,10 @@ export async function jestInitGeneratorInternal(
nxJson.useInferencePlugins !== false;
options.addPlugin ??= addPluginDefault;

const presetExt = isPresetCjs(tree) ? 'cjs' : 'js';
const presetExt = getPresetExt(tree);

if (!tree.exists('jest.preset.js') && !tree.exists('jest.preset.cjs')) {
updateProductionFileSet(tree, presetExt);
if (!tree.exists(`jest.preset.${presetExt}`)) {
updateProductionFileSet(tree);
if (options.addPlugin) {
await addPlugin(
tree,
Expand Down
49 changes: 49 additions & 0 deletions packages/jest/src/utils/config/config-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { readJson, type Tree } from '@nx/devkit';

export const jestConfigExtensions = [
'js',
'ts',
'mjs',
'cjs',
'mts',
'cts',
] as const;
export type JestConfigExtension = typeof jestConfigExtensions[number];

export const jestPresetExtensions = ['js', 'cjs', 'mjs'] as const;
export type JestPresetExtension = typeof jestPresetExtensions[number];

export function getPresetExt(tree: Tree): JestPresetExtension {
const ext = jestPresetExtensions.find((ext) =>
tree.exists(`jest.preset.${ext}`)
);

if (ext) {
return ext;
}

const rootPkgJson = readJson(tree, 'package.json');
if (rootPkgJson.type && rootPkgJson.type === 'module') {
// use cjs if package.json type is module
return 'cjs';
}

// default to js
return 'js';
}

export function findRootJestConfig(tree: Tree): string | null {
const ext = jestConfigExtensions.find((ext) =>
tree.exists(`jest.config.${ext}`)
);

return ext ? `jest.config.${ext}` : null;
}

export function findRootJestPreset(tree: Tree): string | null {
const ext = jestPresetExtensions.find((ext) =>
tree.exists(`jest.preset.${ext}`)
);

return ext ? `jest.preset.${ext}` : null;
}
25 changes: 0 additions & 25 deletions packages/jest/src/utils/config/find-root-jest-files.ts

This file was deleted.

14 changes: 0 additions & 14 deletions packages/jest/src/utils/config/is-preset-cjs.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ if (swcJestConfig.swcrc === undefined) {

<% if(js) {%>module.exports =<% } else { %>export default<% } %> {
displayName: '<%= project %>',
preset: '<%= offsetFromRoot %>jest.preset.js',
preset: '<%= offsetFromRoot %><%= jestPreset %>',
transform: {
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
Expand Down
10 changes: 10 additions & 0 deletions packages/js/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,10 +603,12 @@ function replaceJestConfig(tree: Tree, options: NormalizedSchema) {
if (tree.exists(existingJestConfig)) {
tree.delete(existingJestConfig);
}
const jestPreset = findRootJestPreset(tree) ?? 'jest.presets.js';

// replace with JS:SWC specific jest config
generateFiles(tree, filesDir, options.projectRoot, {
ext: options.js ? 'js' : 'ts',
jestPreset,
js: !!options.js,
project: options.name,
offsetFromRoot: offsetFromRoot(options.projectRoot),
Expand Down Expand Up @@ -1013,4 +1015,12 @@ function logNxReleaseDocsInfo() {
});
}

function findRootJestPreset(tree: Tree): string | null {
const ext = ['js', 'cjs', 'mjs'].find((ext) =>
tree.exists(`jest.preset.${ext}`)
);

return ext ? `jest.preset.${ext}` : null;
}

export default libraryGenerator;
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'nx/src/internal-testing-utils/mock-project-graph';

import { Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { applicationGenerator } from '../application/application';
Expand Down
4 changes: 4 additions & 0 deletions packages/node/src/generators/e2e-project/e2e-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
replaceOverridesInLintConfig,
} from '@nx/eslint/src/generators/utils/eslint-file';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { findRootJestPreset } from '@nx/jest/src/utils/config/config-file';

export async function e2eProjectGenerator(host: Tree, options: Schema) {
return await e2eProjectGeneratorInternal(host, {
Expand Down Expand Up @@ -90,6 +91,7 @@ export async function e2eProjectGeneratorInternal(
});
}

const jestPreset = findRootJestPreset(host) ?? 'jest.preset.js';
if (options.projectType === 'server') {
generateFiles(
host,
Expand All @@ -99,6 +101,7 @@ export async function e2eProjectGeneratorInternal(
...options,
...names(options.rootProject ? 'server' : options.project),
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
jestPreset,
tmpl: '',
}
);
Expand Down Expand Up @@ -127,6 +130,7 @@ export async function e2eProjectGeneratorInternal(
...names(options.rootProject ? 'cli' : options.project),
mainFile,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
jestPreset,
tmpl: '',
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable */
export default {
displayName: '<%= e2eProjectName %>',
preset: '<%= offsetFromRoot %>/jest.preset.js',
preset: '<%= offsetFromRoot %><%= jestPreset %>',
setupFiles: ['<rootDir>/src/test-setup.ts'],
testEnvironment: 'node',
transform: {
Expand All @@ -10,5 +10,5 @@ export default {
}],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '<%= offsetFromRoot %>/coverage/<%= e2eProjectName %>',
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= e2eProjectName %>',
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable */
export default {
displayName: '<%= e2eProjectName %>',
preset: '<%= offsetFromRoot %>jest.preset.js',
preset: '<%= offsetFromRoot %><%= jestPreset %>',
globalSetup: '<rootDir>/src/support/global-setup.ts',
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
Expand Down