mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52477 Changelog: [Internal] This adds a Fantom test for https://github.com/facebook/react-native/blob/main/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js to test a C++ Turbo Module End 2 End (loading the C++ implementation in native code, accessing in JavaScript via Hermes VM and verifying the results of the API calls) Reviewed By: rshest Differential Revision: D77848654 fbshipit-source-id: 48a4ab88a330e9282ae8dab589743eaace62d124
352 lines
12 KiB
JavaScript
352 lines
12 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict-local
|
|
* @format
|
|
*/
|
|
|
|
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
|
import type {
|
|
BinaryTreeNode,
|
|
GraphNode,
|
|
ObjectStruct,
|
|
} from '../NativeCxxModuleExample';
|
|
|
|
import NativeCxxModuleExample, {
|
|
EnumInt,
|
|
EnumNone,
|
|
EnumStr,
|
|
} from '../NativeCxxModuleExample';
|
|
import RCTDeviceEventEmitter from 'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter';
|
|
import NativeFantom from 'react-native/src/private/testing/fantom/specs/NativeFantom';
|
|
|
|
describe('NativeCxxModuleExample', () => {
|
|
it('verifies that the Turbo Module was loaded', () => {
|
|
expect(NativeCxxModuleExample).not.toBeNull();
|
|
});
|
|
|
|
it('verifies getArray(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getArray([])).toEqual([]);
|
|
expect(NativeCxxModuleExample?.getArray([null])).toEqual([null]);
|
|
expect(NativeCxxModuleExample?.getArray([{a: 1, b: '2'}])).toEqual([
|
|
{a: 1, b: '2'},
|
|
]);
|
|
});
|
|
|
|
it('verifies getBool(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getBool(false)).toBe(false);
|
|
expect(NativeCxxModuleExample?.getBool(true)).toBe(true);
|
|
});
|
|
|
|
it('verifies getConstants(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getConstants()).toEqual({
|
|
const1: true,
|
|
const2: 69,
|
|
const3: 'react-native',
|
|
});
|
|
});
|
|
|
|
it('verifies getCustomEnum(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getCustomEnum(EnumInt.IA)).toBe(EnumInt.IA);
|
|
});
|
|
|
|
it('verifies getCustomHostObject(...) returns the correct values', () => {
|
|
const customHostObject = NativeCxxModuleExample?.getCustomHostObject();
|
|
expect(customHostObject).not.toBe(null);
|
|
if (customHostObject != null) {
|
|
expect(
|
|
NativeCxxModuleExample?.consumeCustomHostObject(customHostObject),
|
|
).toBe('answer42');
|
|
}
|
|
});
|
|
|
|
it('verifies getBinaryTreeNode(...) returns the correct values', () => {
|
|
const binaryTreeNode: BinaryTreeNode = {
|
|
left: {value: 2},
|
|
value: 4,
|
|
right: {value: 6},
|
|
};
|
|
const result = NativeCxxModuleExample?.getBinaryTreeNode(binaryTreeNode);
|
|
expect(result).not.toBe(null);
|
|
if (result != null) {
|
|
expect(result.left?.left).toBeNull();
|
|
expect(result.left?.value).toBe(2);
|
|
expect(result.left?.right).toBeNull();
|
|
expect(result.value).toBe(4);
|
|
expect(result.right?.left).toBeNull();
|
|
expect(result.right?.value).toBe(6);
|
|
expect(result.right?.right).toBeNull();
|
|
}
|
|
});
|
|
|
|
it('verifies getGraphNode(...) returns the correct values', () => {
|
|
const graphNode: GraphNode = {
|
|
label: 'root',
|
|
neighbors: [{label: 'child1'}, {label: 'child2'}],
|
|
};
|
|
const result = NativeCxxModuleExample?.getGraphNode(graphNode);
|
|
expect(result).not.toBe(null);
|
|
if (result != null) {
|
|
expect(result.label).toBe('root');
|
|
expect(result.neighbors?.length).toBe(4);
|
|
expect(result.neighbors?.[0].label).toBe('child1');
|
|
expect(result.neighbors?.[0].neighbors).toBeNull();
|
|
expect(result.neighbors?.[1].label).toBe('child2');
|
|
expect(result.neighbors?.[1].neighbors).toBeNull();
|
|
expect(result.neighbors?.[2].label).toBe('top');
|
|
expect(result.neighbors?.[2].neighbors).toBeNull();
|
|
expect(result.neighbors?.[3].label).toBe('down');
|
|
expect(result.neighbors?.[3].neighbors).toBeNull();
|
|
}
|
|
});
|
|
|
|
it('verifies getNumEnum(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getNumEnum(EnumInt.IA)).toBe(EnumInt.IA);
|
|
expect(NativeCxxModuleExample?.getNumEnum(EnumInt.IB)).toBe(EnumInt.IB);
|
|
});
|
|
|
|
it('verifies getStrEnum(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getStrEnum(EnumNone.NA)).toBe(EnumStr.SB);
|
|
expect(NativeCxxModuleExample?.getStrEnum(EnumNone.NB)).toBe(EnumStr.SB);
|
|
});
|
|
|
|
it('verifies getMap(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getMap({a: 0, b: null, c: 3})).toEqual({
|
|
a: 0,
|
|
b: null,
|
|
c: 3,
|
|
});
|
|
});
|
|
|
|
it('verifies getNumber(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getNumber(0)).toBe(0);
|
|
expect(NativeCxxModuleExample?.getNumber(Math.pow(2, 53))).toBe(
|
|
Math.pow(2, 53),
|
|
);
|
|
});
|
|
|
|
it('verifies getObject(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getObject({a: 2, b: 'two'})).toEqual({
|
|
a: 2,
|
|
b: 'two',
|
|
});
|
|
expect(
|
|
NativeCxxModuleExample?.getObject({a: 4, b: 'four', c: 'seven'}),
|
|
).toEqual({a: 4, b: 'four', c: 'seven'});
|
|
});
|
|
|
|
it('verifies getSet(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getSet([1, 2, 3, 3, 3])).toEqual([1, 2, 3]);
|
|
});
|
|
|
|
it('verifies getString(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getString('')).toBe('');
|
|
expect(NativeCxxModuleExample?.getString('string')).toBe('string');
|
|
});
|
|
|
|
it('verifies getUnion(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getUnion(2.88, 'Two', {value: 2})).toBe(
|
|
'x: 2.88, y: Two, z: { value: 2 }',
|
|
);
|
|
expect(NativeCxxModuleExample?.getUnion(5.76, 'One', {low: 'value'})).toBe(
|
|
'x: 5.76, y: One, z: { low: value }',
|
|
);
|
|
});
|
|
|
|
it('verifies getValue(...) returns the correct values', () => {
|
|
expect(
|
|
NativeCxxModuleExample?.getValue(23, 'forty-two', {
|
|
a: 4,
|
|
b: 'four',
|
|
c: 'seven',
|
|
}),
|
|
).toEqual({x: 23, y: 'forty-two', z: {a: 4, b: 'four', c: 'seven'}});
|
|
});
|
|
|
|
it('verifies getValueWithCallback(...) returns the correct values', () => {
|
|
let result = '';
|
|
NativeCxxModuleExample?.getValueWithCallback((value: string) => {
|
|
result = value;
|
|
});
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callback
|
|
expect(result).toBe('value from callback!');
|
|
});
|
|
|
|
it('verifies setValueCallbackWithSubscription(...) returns the correct values', () => {
|
|
let result = '';
|
|
let subscription = NativeCxxModuleExample?.setValueCallbackWithSubscription(
|
|
(value: string) => {
|
|
result = value;
|
|
},
|
|
);
|
|
expect(result).toBe('');
|
|
expect(subscription).not.toBeNull();
|
|
subscription?.();
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callback
|
|
expect(result).toBe('value from callback on clean up!');
|
|
});
|
|
|
|
it('verifies getValueWithPromise(...) returns the correct values', () => {
|
|
{
|
|
let result = '';
|
|
let error = '';
|
|
NativeCxxModuleExample?.getValueWithPromise(false)
|
|
.then(value => {
|
|
result = value;
|
|
})
|
|
.catch(err => {
|
|
error = err;
|
|
});
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callbacks
|
|
expect(result).toBe('result!');
|
|
expect(error).toBe('');
|
|
}
|
|
{
|
|
let result = '';
|
|
let error = '';
|
|
NativeCxxModuleExample?.getValueWithPromise(true)
|
|
.then(value => {
|
|
result = value;
|
|
})
|
|
.catch(err => {
|
|
error = err;
|
|
});
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callbacks
|
|
expect(result).toBe('');
|
|
expect(error.toString()).toBe('Error: intentional promise rejection');
|
|
}
|
|
|
|
it('verifies getWithWithOptionalArgs(...) returns the correct values', () => {
|
|
expect(NativeCxxModuleExample?.getWithWithOptionalArgs()).toBeNull();
|
|
expect(NativeCxxModuleExample?.getWithWithOptionalArgs(true)).toBe(true);
|
|
expect(NativeCxxModuleExample?.getWithWithOptionalArgs(false)).toBe(
|
|
false,
|
|
);
|
|
});
|
|
|
|
it('verifies voidFunc(...) returns the correct for EventEmitters', () => {
|
|
let eventEmitterCalled = {
|
|
onPress: 0,
|
|
onClick: 0,
|
|
onChange: 0,
|
|
onSubmit: 0,
|
|
onEvent: 0,
|
|
};
|
|
let onClickValue: ?string = null;
|
|
let onChangeValue: ?ObjectStruct = null;
|
|
let onSubmitValue: ?(ObjectStruct[]) = null;
|
|
let onEventValue: ?EnumNone = null;
|
|
NativeCxxModuleExample?.onPress(() => {
|
|
eventEmitterCalled.onPress++;
|
|
});
|
|
NativeCxxModuleExample?.onClick((value: string) => {
|
|
eventEmitterCalled.onClick++;
|
|
onClickValue = value;
|
|
});
|
|
NativeCxxModuleExample?.onChange((value: ObjectStruct) => {
|
|
eventEmitterCalled.onChange++;
|
|
onChangeValue = value;
|
|
});
|
|
NativeCxxModuleExample?.onSubmit((value: ObjectStruct[]) => {
|
|
eventEmitterCalled.onSubmit++;
|
|
onSubmitValue = value;
|
|
});
|
|
NativeCxxModuleExample?.onEvent((value: EnumNone) => {
|
|
eventEmitterCalled.onEvent++;
|
|
onEventValue = value;
|
|
});
|
|
NativeCxxModuleExample?.voidFunc();
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callbacks
|
|
|
|
expect(eventEmitterCalled.onPress).toBe(1);
|
|
expect(eventEmitterCalled.onClick).toBe(1);
|
|
expect(eventEmitterCalled.onChange).toBe(1);
|
|
expect(eventEmitterCalled.onSubmit).toBe(1);
|
|
expect(eventEmitterCalled.onEvent).toBe(1);
|
|
|
|
expect(onClickValue).toBe('value from callback on click!');
|
|
expect(onChangeValue).toEqual({a: 1, b: 'two'});
|
|
expect(onSubmitValue).toEqual([
|
|
{a: 1, b: 'two'},
|
|
{a: 3, b: 'four'},
|
|
{a: 5, b: 'six'},
|
|
]);
|
|
expect(onEventValue).toBe(EnumNone.NA);
|
|
});
|
|
});
|
|
|
|
it('verifies voidPromise(...) returns the correct values', () => {
|
|
let promiseCalled = {
|
|
result: 0,
|
|
error: 0,
|
|
};
|
|
NativeCxxModuleExample?.voidPromise()
|
|
.then(_value => promiseCalled.result++)
|
|
.catch(_err => promiseCalled.error++);
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callbacks
|
|
expect(promiseCalled.result).toBe(1);
|
|
expect(promiseCalled.error).toBe(0);
|
|
});
|
|
|
|
it('verifies setMenu(...) returns the correct values', () => {
|
|
let result: {[key: string]: ?{value: string, flag: boolean}} = {
|
|
file: null,
|
|
new: null,
|
|
};
|
|
let menu = {
|
|
label: 'File',
|
|
onPress: (value: string, flag: boolean) => {
|
|
result.file = {value, flag};
|
|
},
|
|
items: [
|
|
{
|
|
label: 'new',
|
|
onPress: (value: string, flag: boolean) => {
|
|
result.new = {value, flag};
|
|
},
|
|
},
|
|
],
|
|
};
|
|
NativeCxxModuleExample?.setMenu(menu);
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callback
|
|
expect(result.file?.value).toBe('value');
|
|
expect(result.file?.flag).toBe(true);
|
|
expect(result.new?.value).toBe('another value');
|
|
expect(result.new?.flag).toBe(false);
|
|
});
|
|
|
|
it('verifies emitCustomDeviceEvent(...) returns the correct values', () => {
|
|
let events: {[key: string]: ?string} = {
|
|
foo: null,
|
|
bar: null,
|
|
};
|
|
RCTDeviceEventEmitter.addListener(
|
|
'foo',
|
|
(value: string) => (events.foo = value),
|
|
);
|
|
RCTDeviceEventEmitter.addListener(
|
|
'bar',
|
|
(value: string) => (events.bar = value),
|
|
);
|
|
NativeCxxModuleExample?.emitCustomDeviceEvent('foo');
|
|
NativeCxxModuleExample?.emitCustomDeviceEvent('bar');
|
|
|
|
NativeFantom.flushMessageQueue(); // Flush the message queue to execute the callbacks
|
|
expect(events.foo).toEqual([
|
|
true,
|
|
42,
|
|
'stringArg',
|
|
{type: 'one', level: 2},
|
|
]);
|
|
expect(events.foo).toEqual([
|
|
true,
|
|
42,
|
|
'stringArg',
|
|
{type: 'one', level: 2},
|
|
]);
|
|
});
|
|
});
|