-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move JS-native version check to its own module + unit tests + prefix …
…Obj-C macro w/RCT - The version check that ensures the JS and native versions match is now in its own module for two reasons: it is easier to test and it allows react-native-windows to override just this module to implement its own version check (ex: more advanced checks for RNW-specific code). - Added unit tests for the version checking to specify its behavior more clearly, including parity between dev and prod to avoid prod-only behavior and mitigate SEVs. - Prefixed the Obj-C `#define` with `RCT_` to conform with other RN globals. Test Plan: Ran `yarn jest` to run all tests. Compiled iOS app and launched it, which runs the version check.
- Loading branch information
Showing
6 changed files
with
164 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** | ||
* Copyright (c) 2017-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule ReactNativeVersionCheck | ||
* @flow | ||
*/ | ||
'use strict'; | ||
|
||
const {PlatformConstants} = require('NativeModules'); | ||
const ReactNativeVersion = require('ReactNativeVersion'); | ||
|
||
/** | ||
* Checks that the version of this React Native JS is compatible with the native | ||
* code, throwing an error if it isn't. | ||
* | ||
* The existence of this module is part of the public interface of React Native | ||
* even though it is used only internally within React Native. React Native | ||
* implementations for other platforms (ex: Windows) may override this module | ||
* and rely on its existence as a separate module. | ||
*/ | ||
exports.checkVersions = function checkVersions(): void { | ||
if (!PlatformConstants) { | ||
return; | ||
} | ||
|
||
const nativeVersion = PlatformConstants.reactNativeVersion; | ||
if ( | ||
ReactNativeVersion.version.major !== nativeVersion.major || | ||
ReactNativeVersion.version.minor !== nativeVersion.minor | ||
) { | ||
throw new Error( | ||
`React Native version mismatch.\n\nJavaScript version: ${_formatVersion( | ||
ReactNativeVersion.version | ||
)}\n` + | ||
`Native version: ${_formatVersion(nativeVersion)}\n\n` + | ||
'Make sure that you have rebuilt the native code. If the problem ' + | ||
'persists try clearing the Watchman and packager caches with ' + | ||
'`watchman watch-del-all && react-native start --reset-cache`.' | ||
); | ||
} | ||
}; | ||
|
||
function _formatVersion(version): string { | ||
return ( | ||
`${version.major}.${version.minor}.${version.patch}` + | ||
(version.prerelease !== null ? `-${version.prerelease}` : '') | ||
); | ||
} |
105 changes: 105 additions & 0 deletions
105
Libraries/Core/__tests__/ReactNativeVersionCheck-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/** | ||
* Copyright (c) 2017-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
'use strict'; | ||
|
||
describe('checkVersion', () => { | ||
describe('in development', () => { | ||
_setDevelopmentModeForTests(true); | ||
_defineCheckVersionTests(); | ||
}); | ||
|
||
describe('in production', () => { | ||
_setDevelopmentModeForTests(false); | ||
_defineCheckVersionTests(); | ||
}); | ||
}); | ||
|
||
function _setDevelopmentModeForTests(dev) { | ||
let originalDev; | ||
|
||
beforeAll(() => { | ||
originalDev = global.__DEV__; | ||
global.__DEV__ = dev; | ||
}); | ||
|
||
afterAll(() => { | ||
global.__DEV__ = originalDev; | ||
}); | ||
} | ||
|
||
function _defineCheckVersionTests() { | ||
afterEach(() => { | ||
jest.resetModules(); | ||
}); | ||
|
||
it('passes when all the versions are zero', () => { | ||
jest.dontMock('ReactNativeVersion'); | ||
_mockNativeVersion(0, 0, 0); | ||
|
||
const ReactNativeVersion = require('ReactNativeVersion'); | ||
const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); | ||
expect(ReactNativeVersion).toMatchObject({ | ||
version: {major: 0, minor: 0, patch: 0, prerelease: null}, | ||
}); | ||
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow(); | ||
}); | ||
|
||
it('passes when the minor matches when the major is zero', () => { | ||
_mockJsVersion(0, 1, 0); | ||
_mockNativeVersion(0, 1, 0); | ||
|
||
const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); | ||
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow(); | ||
}); | ||
|
||
it("throws when the minor doesn't match when the major is zero", () => { | ||
_mockJsVersion(0, 1, 0); | ||
_mockNativeVersion(0, 2, 0); | ||
|
||
const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); | ||
expect(() => ReactNativeVersionCheck.checkVersions()).toThrowError( | ||
/React Native version mismatch/ | ||
); | ||
}); | ||
|
||
it("doesn't throw if the patch doesn't match", () => { | ||
_mockJsVersion(0, 1, 0); | ||
_mockNativeVersion(0, 1, 2); | ||
|
||
const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); | ||
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow(); | ||
}); | ||
|
||
it("doesn't throw if the prerelease doesn't match", () => { | ||
_mockJsVersion(0, 1, 0, 'beta.0'); | ||
_mockNativeVersion(0, 1, 0, 'alpha.1'); | ||
|
||
const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); | ||
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow(); | ||
}); | ||
} | ||
|
||
function _mockJsVersion(major = 0, minor = 0, patch = 0, prerelease = null) { | ||
jest.doMock('ReactNativeVersion', () => ({ | ||
version: {major, minor, patch, prerelease}, | ||
})); | ||
} | ||
|
||
function _mockNativeVersion( | ||
major = 0, | ||
minor = 0, | ||
patch = 0, | ||
prerelease = null | ||
) { | ||
jest.doMock('NativeModules', () => ({ | ||
PlatformConstants: { | ||
reactNativeVersion: {major, minor, patch, prerelease}, | ||
}, | ||
})); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters