Skip to content

Commit efccff7

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Migrate Core, BatchedBridge, and feature-flag Jest tests to Fantom
Summary: Migrates runtime infrastructure unit tests from regular Jest (`-test.js`) to Fantom (`-itest.js`): `parseErrorStack`, `parseHermesStack`, `ReactNativeVersionCheck`, `ReactNativeAttributePayload`, `MessageQueue`, `TracingStateObserver`, and the JS-only portion of `ReactNativeFeatureFlags`. `ReactNativeFeatureFlags` is split: the JS-only cases moved to Fantom, while four cases that assert on the native feature-flag spec (which require module mocking) remain in the Jest file for now. Several tests remain on Jest because they fundamentally depend on capabilities Fantom does not provide (module mocks and/or jest fake timers): `ExceptionsManager`, `loadBundleFromServer`, `JSTimers`, `NativeModules`, and `FabricUIManager`. Changelog: [Internal] Differential Revision: D108759080
1 parent 753fdf9 commit efccff7

9 files changed

Lines changed: 262 additions & 263 deletions

File tree

packages/react-native/Libraries/BatchedBridge/__tests__/MessageQueue-test.js renamed to packages/react-native/Libraries/BatchedBridge/__tests__/MessageQueue-itest.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
* @format
99
*/
1010

11-
'use strict';
11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
12+
13+
const MessageQueueTestModule = require('../__mocks__/MessageQueueTestModule');
14+
const MessageQueue = require('../MessageQueue').default;
1215

13-
let MessageQueue;
14-
let MessageQueueTestModule;
1516
let queue;
1617

1718
const MODULE_IDS = 0;
@@ -41,9 +42,6 @@ const assertQueue = (
4142
// local callbacks stored by IDs are cleaned up.
4243
describe('MessageQueue', () => {
4344
beforeEach(() => {
44-
jest.resetModules();
45-
MessageQueue = require('../MessageQueue').default;
46-
MessageQueueTestModule = require('../__mocks__/MessageQueueTestModule');
4745
queue = new MessageQueue();
4846
queue.registerCallableModule(
4947
'MessageQueueTestModule',
@@ -117,9 +115,16 @@ describe('MessageQueue', () => {
117115
it('should throw when calling with unknown module', () => {
118116
const unknownModule = 'UnknownModule',
119117
unknownMethod = 'UnknownMethod';
120-
expect(() =>
121-
queue.__callFunction(unknownModule, unknownMethod, []),
122-
).toThrow(
118+
let thrownError: ?Error;
119+
try {
120+
queue.__callFunction(unknownModule, unknownMethod, []);
121+
} catch (e: unknown) {
122+
if (e instanceof Error) {
123+
thrownError = e;
124+
}
125+
}
126+
expect(thrownError).toBeInstanceOf(Error);
127+
expect(thrownError?.message).toContain(
123128
`Failed to call into JavaScript module method ${unknownModule}.${unknownMethod}()`,
124129
);
125130
});

packages/react-native/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js renamed to packages/react-native/Libraries/Core/Devtools/__tests__/parseErrorStack-itest.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
* @format
99
*/
1010

11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
12+
1113
import parseErrorStack from '../parseErrorStack';
1214

1315
function getFakeError() {
@@ -21,7 +23,6 @@ describe('parseErrorStack', function () {
2123

2224
const firstFrame = stack[0];
2325
expect(firstFrame.methodName).toEqual('getFakeError');
24-
expect(firstFrame.file).toMatch(/parseErrorStack-test\.js$/);
2526
});
2627

2728
it('does not support framesToPop', function () {

packages/react-native/Libraries/Core/Devtools/__tests__/parseHermesStack-test.js renamed to packages/react-native/Libraries/Core/Devtools/__tests__/parseHermesStack-itest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @format
99
*/
1010

11-
'use strict';
11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1212

1313
const parseHermesStack = require('../parseHermesStack').default;
1414

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
12+
13+
import Platform from '../../Utilities/Platform';
14+
15+
const ReactNativeVersion = require('../ReactNativeVersion');
16+
const ReactNativeVersionCheck = require('../ReactNativeVersionCheck');
17+
18+
// Fantom runs the real C++ runtime, so the version sources are mocked manually
19+
// by mutating the (real) modules instead of using jest.mock/resetModules.
20+
//
21+
// The original Jest test ran every case twice (with `__DEV__` true and false).
22+
// `checkVersions()` does not branch on `__DEV__`, so the two runs were
23+
// identical; the cases are run once here to avoid mutating the runtime's
24+
// `__DEV__` value.
25+
describe('checkVersions', () => {
26+
const originalJsVersion = {...ReactNativeVersion.version};
27+
const originalConstants = Platform.constants;
28+
const originalConsoleError = console.error;
29+
30+
let mockConsoleError: JestMockFn<Array<unknown>, unknown>;
31+
32+
beforeEach(() => {
33+
mockConsoleError = jest.fn();
34+
// $FlowFixMe[cannot-write]
35+
console.error = mockConsoleError;
36+
});
37+
38+
afterEach(() => {
39+
_mockJsVersion(
40+
originalJsVersion.major,
41+
originalJsVersion.minor,
42+
originalJsVersion.patch,
43+
originalJsVersion.prerelease,
44+
);
45+
// $FlowFixMe[incompatible-type]
46+
// $FlowFixMe[prop-missing]
47+
Platform.__constants = originalConstants;
48+
// $FlowFixMe[cannot-write]
49+
console.error = originalConsoleError;
50+
});
51+
52+
it('passes when all the versions are zero', () => {
53+
_mockJsVersion(0, 0, 0);
54+
_mockNativeVersion(0, 0, 0);
55+
56+
expect(ReactNativeVersion.version).toEqual({
57+
major: 0,
58+
minor: 0,
59+
patch: 0,
60+
prerelease: null,
61+
});
62+
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow();
63+
});
64+
65+
it('passes when the minor matches when the major is zero', () => {
66+
_mockJsVersion(0, 1, 0);
67+
_mockNativeVersion(0, 1, 0);
68+
69+
expect(() => ReactNativeVersionCheck.checkVersions()).not.toThrow();
70+
});
71+
72+
it("logs error when the minor doesn't match when the major is zero", () => {
73+
_mockJsVersion(0, 1, 0);
74+
_mockNativeVersion(0, 2, 0);
75+
76+
ReactNativeVersionCheck.checkVersions();
77+
expect(mockConsoleError).toHaveBeenCalledTimes(1);
78+
expect(mockConsoleError.mock.calls[0][0]).toContain(
79+
'React Native version mismatch',
80+
);
81+
});
82+
83+
it("logs error when the major doesn't match", () => {
84+
_mockJsVersion(1, 0, 0);
85+
_mockNativeVersion(2, 0, 0);
86+
87+
ReactNativeVersionCheck.checkVersions();
88+
expect(mockConsoleError).toHaveBeenCalledTimes(1);
89+
expect(mockConsoleError.mock.calls[0][0]).toContain(
90+
'React Native version mismatch',
91+
);
92+
});
93+
94+
it("doesn't log error if the patch doesn't match", () => {
95+
_mockJsVersion(0, 1, 0);
96+
_mockNativeVersion(0, 1, 2);
97+
98+
ReactNativeVersionCheck.checkVersions();
99+
expect(mockConsoleError).toHaveBeenCalledTimes(0);
100+
});
101+
102+
it("doesn't log error if the prerelease doesn't match", () => {
103+
_mockJsVersion(0, 1, 0, 'beta.0');
104+
_mockNativeVersion(0, 1, 0, 'alpha.1');
105+
106+
ReactNativeVersionCheck.checkVersions();
107+
expect(mockConsoleError).toHaveBeenCalledTimes(0);
108+
});
109+
});
110+
111+
function _mockJsVersion(
112+
major: number = 0,
113+
minor: number = 0,
114+
patch: number = 0,
115+
prerelease: string | null = null,
116+
) {
117+
ReactNativeVersion.version.major = major;
118+
ReactNativeVersion.version.minor = minor;
119+
ReactNativeVersion.version.patch = patch;
120+
ReactNativeVersion.version.prerelease = prerelease;
121+
}
122+
123+
function _mockNativeVersion(
124+
major: number = 0,
125+
minor: number = 0,
126+
patch: number = 0,
127+
prerelease: string | null = null,
128+
) {
129+
// $FlowFixMe[incompatible-type]
130+
// $FlowFixMe[prop-missing]
131+
Platform.__constants = {
132+
...Platform.constants,
133+
reactNativeVersion: {major, minor, patch, prerelease},
134+
};
135+
}

packages/react-native/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js

Lines changed: 0 additions & 154 deletions
This file was deleted.

packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactNativeAttributePayload-test.js renamed to packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactNativeAttributePayload-itest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @format
99
*/
1010

11-
'use strict';
11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1212

1313
import type {AttributeConfiguration} from '../../../Renderer/shims/ReactNativeTypes';
1414

0 commit comments

Comments
 (0)