diff --git a/packages/cli-doctor/src/tools/healthchecks/__tests__/dependencies.test.ts b/packages/cli-doctor/src/tools/healthchecks/__tests__/dependencies.test.ts new file mode 100644 index 0000000000..da2a17cdd3 --- /dev/null +++ b/packages/cli-doctor/src/tools/healthchecks/__tests__/dependencies.test.ts @@ -0,0 +1,51 @@ +import fs from 'fs'; +import dependencies from '../dependencies'; +import {EnvironmentInfo} from '../../../types'; + +describe('dependencies', () => { + let environmentInfo: EnvironmentInfo; + let dependenciesJSON: string; + + beforeEach(() => { + jest.spyOn(fs, 'readFileSync').mockImplementation(() => dependenciesJSON); + }); + + it('returns false if dependencies are correct', async () => { + dependenciesJSON = JSON.stringify({ + name: 'AwesomeProject', + dependencies: { + 'react-native': '0.72.1', + }, + }); + + const diagnostics = await dependencies.getDiagnostics(environmentInfo); + expect(diagnostics.needsToBeFixed).toBe(false); + }); + + it('returns true if dependencies contains an incompatible version react native package', async () => { + dependenciesJSON = JSON.stringify({ + name: 'AwesomeProject', + dependencies: { + 'react-native': '0.72.1', + '@react-native/codegen': '1.72.3', + '@react-native/gradle-plugin': '0.69.10', + }, + }); + + const diagnostics = await dependencies.getDiagnostics(environmentInfo); + expect(diagnostics.needsToBeFixed).toBe(true); + }); + + it('returns true if dependencies contains an compatible version react native package', async () => { + dependenciesJSON = JSON.stringify({ + name: 'AwesomeProject', + dependencies: { + 'react-native': '0.72.1', + '@react-native/codegen': '0.72.1', + }, + }); + + const diagnostics = await dependencies.getDiagnostics(environmentInfo); + expect(diagnostics.needsToBeFixed).toBe(true); + }); +}); diff --git a/packages/cli-doctor/src/tools/healthchecks/dependencies.ts b/packages/cli-doctor/src/tools/healthchecks/dependencies.ts index 5ccd77a012..aec9381d03 100644 --- a/packages/cli-doctor/src/tools/healthchecks/dependencies.ts +++ b/packages/cli-doctor/src/tools/healthchecks/dependencies.ts @@ -1,4 +1,5 @@ import fs from 'fs'; +import chalk from 'chalk'; import path from 'path'; import semver from 'semver'; import {HealthCheckInterface} from '../../types'; @@ -50,21 +51,31 @@ export default { const root = config?.root || findProjectRoot(); const dependencies = findDependencies(root); const reactNativeVersion = dependencies['react-native']; - const reactNativeMinorVersion = semver.coerce(reactNativeVersion)?.minor; + const reactNativeCoercedVersion = semver.coerce(reactNativeVersion); const issues: string[] = []; RNPackages.forEach((pkg) => { if (dependencies[pkg]) { - issues.push( - ` - ${pkg} is part of React Native and should not be a dependency in your package.json`, - ); const packageVersion = dependencies[pkg]; - const packageMinorVersion = semver.coerce(packageVersion)?.minor; - - if (reactNativeMinorVersion !== packageMinorVersion) { - issues.push( - ` - ${pkg} "${packageVersion}" is not compatible with react-native: "${reactNativeVersion}"`, + const packageCoercedVersion = semver.coerce(packageVersion); + if (reactNativeCoercedVersion && packageCoercedVersion) { + const verisonDiff = semver.diff( + packageCoercedVersion, + reactNativeCoercedVersion, ); + if (verisonDiff === 'major' || verisonDiff === 'minor') { + issues.push( + ` - ${chalk.red.bold( + 'error', + )} ${pkg}: "${packageVersion}" is not compatible with react-native: "${reactNativeVersion}"`, + ); + } else { + issues.push( + ` - ${chalk.yellow.bold( + 'warn', + )} ${pkg} is part of React Native and should not be a dependency in your package.json`, + ); + } } } });