Skip to content

Commit

Permalink
Run ReactFabric-test.internal.js in xplat variant
Browse files Browse the repository at this point in the history
The explicit mock override in this test was causing it to always run as native-oss instead of also as xplat. This moves the test to use `// @GATE persistent` instead to run it in all persistent configs.
  • Loading branch information
kassens committed Jun 26, 2024
1 parent 7baae65 commit e6466d7
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ const SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT =
"sendAccessibilityEvent was called with a ref that isn't a " +
'native component. Use React.forwardRef to get access to the underlying native component';

jest.mock('shared/ReactFeatureFlags', () =>
require('shared/forks/ReactFeatureFlags.native-oss'),
);

describe('ReactFabric', () => {
beforeEach(() => {
jest.resetModules();
Expand All @@ -45,6 +41,7 @@ describe('ReactFabric', () => {
act = require('internal-test-utils').act;
});

// @gate persistent
it('should be able to create and render a native component', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand All @@ -59,6 +56,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.completeRoot).toBeCalled();
});

// @gate persistent
it('should be able to create and update a native component', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -93,6 +91,7 @@ describe('ReactFabric', () => {
});
});

// @gate persistent
it('should not call FabricUIManager.cloneNode after render for properties that have not changed', async () => {
const Text = createReactNativeComponentClass('RCTText', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -164,6 +163,7 @@ describe('ReactFabric', () => {
).toHaveBeenCalledTimes(1);
});

// @gate persistent
it('should only pass props diffs to FabricUIManager.cloneNode', async () => {
const Text = createReactNativeComponentClass('RCTText', () => ({
validAttributes: {foo: true, bar: true},
Expand Down Expand Up @@ -198,9 +198,9 @@ describe('ReactFabric', () => {
).toEqual({
bar: 'b',
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(`11
RCTText {"foo":"a","bar":"b"}
RCTRawText {"text":"1"}`);

await act(() => {
ReactFabric.render(
Expand All @@ -220,11 +220,12 @@ describe('ReactFabric', () => {
).toEqual({
foo: 'b',
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(`11
RCTText {"foo":"b","bar":"b"}
RCTRawText {"text":"2"}`);
});

// @gate persistent
it('should not clone nodes without children when updating props', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -273,6 +274,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.completeRoot).toBeCalled();
});

// @gate persistent
it('should call dispatchCommand for native refs', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -303,6 +305,7 @@ describe('ReactFabric', () => {
);
});

// @gate persistent
it('should warn and no-op if calling dispatchCommand on non native refs', async () => {
class BasicClass extends React.Component {
render() {
Expand Down Expand Up @@ -334,6 +337,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
});

// @gate persistent
it('should call sendAccessibilityEvent for native refs', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -365,6 +369,7 @@ describe('ReactFabric', () => {
);
});

// @gate persistent
it('should warn and no-op if calling sendAccessibilityEvent on non native refs', async () => {
class BasicClass extends React.Component {
render() {
Expand Down Expand Up @@ -396,6 +401,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
});

// @gate persistent
it('returns the correct instance and calls it in the callback', () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand All @@ -417,6 +423,7 @@ describe('ReactFabric', () => {
expect(a).toBe(c);
});

// @gate persistent
it('renders and reorders children', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {title: true},
Expand All @@ -425,6 +432,7 @@ describe('ReactFabric', () => {

class Component extends React.Component {
render() {
// @gate persistent
const chars = this.props.chars.split('');
return (
<View>
Expand All @@ -443,18 +451,57 @@ describe('ReactFabric', () => {
await act(() => {
ReactFabric.render(<Component chars={before} />, 11);
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(`11
RCTView null
RCTView {"title":"a"}
RCTView {"title":"b"}
RCTView {"title":"c"}
RCTView {"title":"d"}
RCTView {"title":"e"}
RCTView {"title":"f"}
RCTView {"title":"g"}
RCTView {"title":"h"}
RCTView {"title":"i"}
RCTView {"title":"j"}
RCTView {"title":"k"}
RCTView {"title":"l"}
RCTView {"title":"m"}
RCTView {"title":"n"}
RCTView {"title":"o"}
RCTView {"title":"p"}
RCTView {"title":"q"}
RCTView {"title":"r"}
RCTView {"title":"s"}
RCTView {"title":"t"}`);

await act(() => {
ReactFabric.render(<Component chars={after} />, 11);
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(`11
RCTView null
RCTView {"title":"m"}
RCTView {"title":"x"}
RCTView {"title":"h"}
RCTView {"title":"p"}
RCTView {"title":"g"}
RCTView {"title":"w"}
RCTView {"title":"f"}
RCTView {"title":"r"}
RCTView {"title":"a"}
RCTView {"title":"l"}
RCTView {"title":"k"}
RCTView {"title":"e"}
RCTView {"title":"o"}
RCTView {"title":"i"}
RCTView {"title":"v"}
RCTView {"title":"c"}
RCTView {"title":"s"}
RCTView {"title":"t"}
RCTView {"title":"z"}
RCTView {"title":"y"}`);
});

// @gate persistent
it('recreates host parents even if only children changed', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {title: true},
Expand All @@ -469,6 +516,7 @@ describe('ReactFabric', () => {
chars: before,
};
render() {
// @gate persistent
const chars = this.state.chars.split('');
return (
<View>
Expand All @@ -490,20 +538,63 @@ describe('ReactFabric', () => {
11,
);
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(
`11
RCTView null
RCTView null
RCTView {"title":"a"}
RCTView {"title":"b"}
RCTView {"title":"c"}
RCTView {"title":"d"}
RCTView {"title":"e"}
RCTView {"title":"f"}
RCTView {"title":"g"}
RCTView {"title":"h"}
RCTView {"title":"i"}
RCTView {"title":"j"}
RCTView {"title":"k"}
RCTView {"title":"l"}
RCTView {"title":"m"}
RCTView {"title":"n"}
RCTView {"title":"o"}
RCTView {"title":"p"}
RCTView {"title":"q"}
RCTView {"title":"r"}
RCTView {"title":"s"}
RCTView {"title":"t"}`,
);

// Call setState() so that we skip over the top-level host node.
// It should still get recreated despite a bailout.
ref.current.setState({
chars: after,
});
expect(
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
).toMatchSnapshot();
expect(nativeFabricUIManager.__dumpHierarchyForJestTestsOnly()).toBe(`11
RCTView null
RCTView null
RCTView {"title":"m"}
RCTView {"title":"x"}
RCTView {"title":"h"}
RCTView {"title":"p"}
RCTView {"title":"g"}
RCTView {"title":"w"}
RCTView {"title":"f"}
RCTView {"title":"r"}
RCTView {"title":"a"}
RCTView {"title":"l"}
RCTView {"title":"k"}
RCTView {"title":"e"}
RCTView {"title":"o"}
RCTView {"title":"i"}
RCTView {"title":"v"}
RCTView {"title":"c"}
RCTView {"title":"s"}
RCTView {"title":"t"}
RCTView {"title":"z"}
RCTView {"title":"y"}`);
});

// @gate persistent
it('calls setState with no arguments', async () => {
let mockArgs;
class Component extends React.Component {
Expand All @@ -521,6 +612,7 @@ describe('ReactFabric', () => {
expect(mockArgs.length).toEqual(0);
});

// @gate persistent
it('should call complete after inserting children', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand All @@ -544,9 +636,13 @@ describe('ReactFabric', () => {
22,
);
});
expect(snapshots).toMatchSnapshot();
expect(snapshots).toEqual([
`RCTView {"foo":"a"}
RCTView {"foo":"b"}`,
]);
});

// @gate persistent
it('should not throw when <View> is used inside of a <Text> ancestor', async () => {
const Image = createReactNativeComponentClass('RCTImage', () => ({
validAttributes: {},
Expand Down Expand Up @@ -580,6 +676,7 @@ describe('ReactFabric', () => {
});
});

// @gate persistent
it('should console error for text not inside of a <Text> ancestor', async () => {
const ScrollView = createReactNativeComponentClass('RCTScrollView', () => ({
validAttributes: {},
Expand Down Expand Up @@ -612,6 +709,7 @@ describe('ReactFabric', () => {
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
});

// @gate persistent
it('should not throw for text inside of an indirect <Text> ancestor', async () => {
const Text = createReactNativeComponentClass('RCTText', () => ({
validAttributes: {},
Expand All @@ -630,6 +728,7 @@ describe('ReactFabric', () => {
});
});

// @gate persistent
it('dispatches events to the last committed props', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {},
Expand Down Expand Up @@ -684,6 +783,7 @@ describe('ReactFabric', () => {
});

describe('skipBubbling', () => {
// @gate persistent
it('should skip bubbling to ancestor if specified', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {},
Expand Down Expand Up @@ -777,6 +877,7 @@ describe('ReactFabric', () => {
});
});

// @gate persistent
it('dispatches event with target as instance', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {
Expand Down Expand Up @@ -868,6 +969,7 @@ describe('ReactFabric', () => {
expect.assertions(6);
});

// @gate persistent
it('findHostInstance_DEPRECATED should warn if used to find a host component inside StrictMode', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -909,6 +1011,7 @@ describe('ReactFabric', () => {
expect(match).toBe(child);
});

// @gate persistent
it('findHostInstance_DEPRECATED should warn if passed a component that is inside StrictMode', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -948,6 +1051,7 @@ describe('ReactFabric', () => {
expect(match).toBe(child);
});

// @gate persistent
it('findNodeHandle should warn if used to find a host component inside StrictMode', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -989,6 +1093,7 @@ describe('ReactFabric', () => {
);
});

// @gate persistent
it('findNodeHandle should warn if passed a component that is inside StrictMode', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -1028,6 +1133,7 @@ describe('ReactFabric', () => {
);
});

// @gate persistent
it('should no-op if calling sendAccessibilityEvent on unmounted refs', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -1060,6 +1166,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
});

// @gate persistent
it('getNodeFromInternalInstanceHandle should return the correct shadow node', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand All @@ -1084,6 +1191,7 @@ describe('ReactFabric', () => {
expect(node).toBe(expectedShadowNode);
});

// @gate persistent
it('getPublicInstanceFromInternalInstanceHandle should provide public instances for HostComponent', async () => {
const View = createReactNativeComponentClass('RCTView', () => ({
validAttributes: {foo: true},
Expand Down Expand Up @@ -1124,6 +1232,7 @@ describe('ReactFabric', () => {
expect(publicInstanceAfterUnmount).toBe(null);
});

// @gate persistent
it('getPublicInstanceFromInternalInstanceHandle should provide public instances for HostText', async () => {
jest.spyOn(ReactNativePrivateInterface, 'createPublicTextInstance');

Expand Down
Loading

0 comments on commit e6466d7

Please sign in to comment.