From f27798631627306fb34543fd85671f34fd17be2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Fri, 9 Aug 2024 12:26:57 +0200 Subject: [PATCH] feat(testing): allow usage of jest 30 pre-release versions --- packages/jest/package.json | 1 + packages/jest/plugins/resolver.ts | 14 +------ packages/jest/src/plugins/plugin.ts | 53 +++++++++++++++--------- packages/jest/src/utils/version-utils.ts | 15 +++++++ 4 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 packages/jest/src/utils/version-utils.ts diff --git a/packages/jest/package.json b/packages/jest/package.json index 1cab03672cae4..438ec0c8e4a80 100644 --- a/packages/jest/package.json +++ b/packages/jest/package.json @@ -47,6 +47,7 @@ "jest-util": "^29.4.1", "minimatch": "9.0.3", "resolve.exports": "1.1.0", + "semver": "^7.5.3", "tslib": "^2.3.0", "yargs-parser": "21.1.1" }, diff --git a/packages/jest/plugins/resolver.ts b/packages/jest/plugins/resolver.ts index 9cdd26d2fb036..33c8b0303d1df 100644 --- a/packages/jest/plugins/resolver.ts +++ b/packages/jest/plugins/resolver.ts @@ -1,16 +1,6 @@ import { dirname, extname, join, resolve } from 'path'; import { resolve as resolveExports } from 'resolve.exports'; -import type defaultResolver from 'jest-resolve/build/defaultResolver'; - -interface ResolveOptions { - rootDir: string; - basedir: string; - paths: string[]; - moduleDirectory: string[]; - browser: boolean; - extensions: string[]; - defaultResolver: typeof defaultResolver; -} +import type { ResolverOptions } from 'jest-resolve'; let compilerSetup; let ts; @@ -38,7 +28,7 @@ function getCompilerSetup(rootDir: string) { return { compilerOptions, host }; } -module.exports = function (path: string, options: ResolveOptions) { +module.exports = function (path: string, options: ResolverOptions) { const ext = extname(path); if (ext === '.css' || ext === '.scss' || ext === '.sass' || ext === '.less') { return require.resolve('identity-obj-proxy'); diff --git a/packages/jest/src/plugins/plugin.ts b/packages/jest/src/plugins/plugin.ts index 91569f2d37b18..5245ddeb38ddf 100644 --- a/packages/jest/src/plugins/plugin.ts +++ b/packages/jest/src/plugins/plugin.ts @@ -1,3 +1,4 @@ +import type { Config } from '@jest/types'; import { CreateNodes, CreateNodesContext, @@ -13,22 +14,20 @@ import { TargetConfiguration, writeJsonFile, } from '@nx/devkit'; -import { dirname, isAbsolute, join, relative, resolve } from 'path'; - -import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; -import { existsSync, readdirSync, readFileSync } from 'fs'; -import { readConfig, replaceRootDirInPath } from 'jest-config'; -import jestResolve from 'jest-resolve'; -import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { clearRequireCache, loadConfigFile, } from '@nx/devkit/src/utils/config-utils'; -import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json'; -import { combineGlobPatterns } from 'nx/src/utils/globs'; +import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; +import { existsSync, readdirSync, readFileSync } from 'fs'; import { minimatch } from 'minimatch'; import { hashObject } from 'nx/src/devkit-internals'; +import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json'; +import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; +import { combineGlobPatterns } from 'nx/src/utils/globs'; +import { dirname, isAbsolute, join, relative, resolve } from 'path'; +import { getInstalledJestMajorVersion } from '../utils/version-utils'; const pmc = getPackageManagerCommand(); @@ -167,6 +166,12 @@ async function buildJestTargets( } const rawConfig = await loadConfigFile(absConfigFilePath); + + const { readConfig } = requireJestUtil( + 'jest-config', + projectRoot, + context.workspaceRoot + ); const config = await readConfig( { _: [], @@ -215,7 +220,7 @@ async function buildJestTargets( const { default: Runtime } = requireJestUtil( 'jest-runtime', projectRoot, - context + context.workspaceRoot ); const jestContext = await Runtime.createContext(config.projectConfig, { @@ -225,11 +230,16 @@ async function buildJestTargets( const jest = require(resolveJestPath( projectRoot, - context + context.workspaceRoot )) as typeof import('jest'); const source = new jest.SearchSource(jestContext); - const specs = await source.getTestPaths(config.globalConfig); + const jestVersion = getInstalledJestMajorVersion()!; + const specs = + jestVersion >= 30 + ? // @ts-expect-error Jest 30+ expects the project config as the second argument + await source.getTestPaths(config.globalConfig, config.projectConfig) + : await source.getTestPaths(config.globalConfig); const testPaths = new Set(specs.tests.map(({ path }) => path)); @@ -345,11 +355,17 @@ function resolvePresetInput( return null; } + const { replaceRootDirInPath } = requireJestUtil< + typeof import('jest-config') + >('jest-config', projectRoot, workspaceRoot); let presetPath = replaceRootDirInPath(projectRoot, presetValue); const isNpmPackage = !presetValue.startsWith('.') && !isAbsolute(presetPath); presetPath = presetPath.startsWith('.') ? presetPath : join(presetPath, 'jest-preset'); + const { default: jestResolve } = requireJestUtil< + typeof import('jest-resolve') + >('jest-resolve', projectRoot, workspaceRoot); const presetModule = jestResolve.findNodeModule(presetPath, { basedir: projectRoot, extensions: ['.json', '.js', '.cjs', '.mjs'], @@ -371,7 +387,7 @@ function resolvePresetInput( function getOutputs( projectRoot: string, - { globalConfig }: Awaited>, + { globalConfig }: { globalConfig: Config.GlobalConfig }, context: CreateNodesContext ): string[] { function getOutput(path: string): string { @@ -407,17 +423,14 @@ function normalizeOptions(options: JestPluginOptions): JestPluginOptions { } let resolvedJestPaths: Record; -function resolveJestPath( - projectRoot: string, - context: CreateNodesContext -): string { +function resolveJestPath(projectRoot: string, workspaceRoot: string): string { resolvedJestPaths ??= {}; if (resolvedJestPaths[projectRoot]) { return resolvedJestPaths[projectRoot]; } return require.resolve('jest', { - paths: [projectRoot, context.workspaceRoot, __dirname], + paths: [projectRoot, workspaceRoot, __dirname], }); } @@ -427,9 +440,9 @@ function resolveJestPath( function requireJestUtil( packageName: string, projectRoot: string, - context: CreateNodesContext + workspaceRoot: string ): T { - const jestPath = resolveJestPath(projectRoot, context); + const jestPath = resolveJestPath(projectRoot, workspaceRoot); return require(require.resolve(packageName, { paths: [dirname(jestPath)] })); } diff --git a/packages/jest/src/utils/version-utils.ts b/packages/jest/src/utils/version-utils.ts new file mode 100644 index 0000000000000..da6633f3fa678 --- /dev/null +++ b/packages/jest/src/utils/version-utils.ts @@ -0,0 +1,15 @@ +import { major } from 'semver'; + +export function getInstalledJestVersion(): string | null { + try { + return require('jest/package.json').version; + } catch { + return null; + } +} + +export function getInstalledJestMajorVersion(): number | null { + const installedVersion = getInstalledJestVersion(); + + return installedVersion ? major(installedVersion) : null; +}