Skip to content

Commit b968786

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Migrate Utilities and EventEmitter Jest tests to Fantom
Summary: Migrates 17 unit tests from regular Jest (`-test.js`) to Fantom (`-itest.js`) under `Libraries/Utilities` (and `Libraries/Utilities/differ`) and `Libraries/vendor/emitter`, so this runtime client code is tested on Hermes in the real React Native runtime. Migrated: `binaryToBase64`, `deepFreezeAndThrowOnMutationInDev`, `DeviceInfo`, `Dimensions`, `logError`, `mapWithSeparator`, `PixelRatio`, `Platform`, `SceneTracker`, `stringifySafe`, `useColorScheme`, `useMergeRefs`, `useRefEffect`, `warnOnce`, `differ/deepDiffer`, `differ/matricesDiffer`, and `EventEmitter`. Adaptations (no behavioral coverage weakened): - Replaced `jest.spyOn(console, ...)` with manual save/replace/restore capture of the `console` method. - Replaced hook/component tests that used `react-test-renderer` with Fantom rendering (`createRoot` + `runTask`), reading hook return values via a small probe component and ref identity via `ensureInstance`. - Adapted a few expected values to the real Hermes/Android runtime (e.g. function `toString` output, `useColorScheme` returning null when native Appearance is unavailable). - Replaced node-only `TextEncoder`/`TextDecoder` usage in `binaryToBase64` with explicit byte construction. Two tests intentionally remain on Jest because they cannot be expressed without module mocking / the test-renderer tree API (both unsupported by Fantom): `codegenNativeComponent` (mocks native component registration) and `ReactNativeTestTools` (tests jest helpers built on the `react-test-renderer` instance tree). Changelog: [Internal] Differential Revision: D108759079
1 parent 567a1a0 commit b968786

20 files changed

Lines changed: 514 additions & 439 deletions

packages/react-native/Libraries/Utilities/__tests__/DeviceInfo-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/DeviceInfo-itest.js

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

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

1313
describe('DeviceInfo', () => {
1414
const DeviceInfo = require('../DeviceInfo').default;
1515

1616
it('should give device info', () => {
17-
expect(DeviceInfo.getConstants()).toHaveProperty('Dimensions');
17+
expect(DeviceInfo.getConstants().Dimensions).toBeDefined();
1818
});
1919
});

packages/react-native/Libraries/Utilities/__tests__/Dimensions-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/Dimensions-itest.js

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

11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1112
import Dimensions from '../Dimensions';
1213
import Platform from '../Platform';
1314

packages/react-native/Libraries/Utilities/__tests__/PixelRatio-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/PixelRatio-itest.js

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

11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1112
import Dimensions from '../Dimensions';
1213
import PixelRatio from '../PixelRatio';
1314

packages/react-native/Libraries/Utilities/__tests__/Platform-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/Platform-itest.js

Lines changed: 2 additions & 0 deletions
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 type {PlatformSelectSpec} from '../PlatformTypes';
1214

1315
// $FlowFixMe[missing-platform-support]

packages/react-native/Libraries/Utilities/__tests__/SceneTracker-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/SceneTracker-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 SceneTracker = require('../SceneTracker').default;
1414

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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
8+
*/
9+
10+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
11+
import binaryToBase64 from '../binaryToBase64';
12+
import base64 from 'base64-js';
13+
14+
describe('binaryToBase64', () => {
15+
it('should encode a Uint8Array', () => {
16+
const bytes = new TextEncoder().encode('Test string');
17+
18+
expect(decodeBase64(binaryToBase64(bytes))).toEqual(Array.from(bytes));
19+
});
20+
21+
it('should encode an ArrayBuffer', () => {
22+
const bytes = new TextEncoder().encode('Test string');
23+
24+
expect(decodeBase64(binaryToBase64(bytes.buffer))).toEqual(
25+
Array.from(bytes),
26+
);
27+
});
28+
29+
it('should encode a DataView', () => {
30+
const bytes = new TextEncoder().encode('Test string');
31+
32+
expect(decodeBase64(binaryToBase64(new DataView(bytes.buffer)))).toEqual(
33+
Array.from(bytes),
34+
);
35+
});
36+
37+
it('should not encode a non-ArrayBuffer or non-TypedArray', () => {
38+
const input = ['i', 'n', 'v', 'a', 'l', 'i', 'd'];
39+
40+
// $FlowExpectedError[incompatible-type]
41+
expect(() => binaryToBase64(input)).toThrow();
42+
});
43+
});
44+
45+
function decodeBase64(base64String: string): Array<number> {
46+
return Array.from(base64.toByteArray(base64String));
47+
}

packages/react-native/Libraries/Utilities/__tests__/binaryToBase64-test.js

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

packages/react-native/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-itest.js

Lines changed: 12 additions & 8 deletions
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
const deepFreezeAndThrowOnMutationInDev =
1214
require('../deepFreezeAndThrowOnMutationInDev').default;
1315

@@ -53,7 +55,7 @@ describe('deepFreezeAndThrowOnMutationInDev', () => {
5355
deepFreezeAndThrowOnMutationInDev(o);
5456
expect(() => {
5557
o.key = 'newValue';
56-
}).toThrowError(
58+
}).toThrow(
5759
'You attempted to set the key `key` with the value `"newValue"` ' +
5860
'on an object that is meant to be immutable and has been frozen.',
5961
);
@@ -66,7 +68,7 @@ describe('deepFreezeAndThrowOnMutationInDev', () => {
6668
deepFreezeAndThrowOnMutationInDev(o);
6769
expect(() => {
6870
o.key = 'newValue';
69-
}).toThrowError(
71+
}).toThrow(
7072
'You attempted to set the key `key` with the value `"newValue"` ' +
7173
'on an object that is meant to be immutable and has been frozen.',
7274
);
@@ -80,7 +82,7 @@ describe('deepFreezeAndThrowOnMutationInDev', () => {
8082
deepFreezeAndThrowOnMutationInDev(o);
8183
expect(() => {
8284
o.key1.key2.key3 = 'newValue';
83-
}).toThrowError(
85+
}).toThrow(
8486
'You attempted to set the key `key3` with the value `"newValue"` ' +
8587
'on an object that is meant to be immutable and has been frozen.',
8688
);
@@ -93,7 +95,7 @@ describe('deepFreezeAndThrowOnMutationInDev', () => {
9395
deepFreezeAndThrowOnMutationInDev(o);
9496
expect(() => {
9597
o.key1.key2.key3 = 'newValue';
96-
}).toThrowError(
98+
}).toThrow(
9799
'You attempted to set the key `key3` with the value `"newValue"` ' +
98100
'on an object that is meant to be immutable and has been frozen.',
99101
);
@@ -105,12 +107,14 @@ describe('deepFreezeAndThrowOnMutationInDev', () => {
105107
__DEV__ = true;
106108
const o = {oldKey: 'value'};
107109
deepFreezeAndThrowOnMutationInDev(o);
108-
expect(() => {
110+
let message;
111+
try {
109112
// $FlowExpectedError[prop-missing]
110113
o.newKey = 'value';
111-
}).toThrowError(
112-
/(Cannot|Can't) add property newKey, object is not extensible/,
113-
);
114+
} catch (error: unknown) {
115+
message = error instanceof Error ? error.message : String(error);
116+
}
117+
expect(message).toMatch(/Cannot add new property 'newKey'/);
114118
// $FlowExpectedError[prop-missing]
115119
expect(o.newKey).toBe(undefined);
116120
});

packages/react-native/Libraries/Utilities/__tests__/logError-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/logError-itest.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,50 @@
88
* @format
99
*/
1010

11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1112
import logError from '../logError';
1213

1314
describe('logError', () => {
15+
const originalConsoleError = console.error;
16+
17+
afterEach(() => {
18+
// $FlowFixMe[cannot-write]
19+
console.error = originalConsoleError;
20+
});
21+
1422
it('logs error messages to the console', () => {
15-
console.error.apply = jest.fn();
23+
const mockConsoleError = jest.fn();
24+
// $FlowFixMe[cannot-write]
25+
console.error = mockConsoleError;
1626

1727
logError('This is a log message');
1828

19-
expect(console.error.apply).toHaveBeenCalledWith(console, [
20-
'This is a log message',
21-
]);
29+
expect(mockConsoleError).toHaveBeenCalledWith('This is a log message');
2230
});
2331

2432
it('logs error messages with multiple arguments to the console', () => {
25-
console.error.apply = jest.fn();
33+
const mockConsoleError = jest.fn();
34+
// $FlowFixMe[cannot-write]
35+
console.error = mockConsoleError;
2636

2737
const data = 'log';
2838
logError('This is a', data, 'message');
2939

30-
expect(console.error.apply).toHaveBeenCalledWith(console, [
40+
expect(mockConsoleError).toHaveBeenCalledWith(
3141
'This is a',
3242
'log',
3343
'message',
34-
]);
44+
);
3545
});
3646

3747
it('logs errors to the console', () => {
48+
const mockConsoleError = jest.fn();
3849
// $FlowFixMe[cannot-write]
39-
console.error = jest.fn();
50+
console.error = mockConsoleError;
4051

4152
logError(new Error('The error message'));
4253

43-
// $FlowFixMe[prop-missing]
44-
expect(console.error.mock.calls[0][0]).toContain(
54+
expect(mockConsoleError.mock.calls[0][0]).toContain(
4555
'Error: "The error message". Stack:',
4656
);
4757
});

packages/react-native/Libraries/Utilities/__tests__/mapWithSeparator-test.js renamed to packages/react-native/Libraries/Utilities/__tests__/mapWithSeparator-itest.js

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

11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
1112
import mapWithSeparator from '../mapWithSeparator';
1213

1314
describe('mapWithSeparator', () => {

0 commit comments

Comments
 (0)