Skip to content

Commit

Permalink
Add xplat test variants (#29734)
Browse files Browse the repository at this point in the history
## Overview

We didn't have any tests that ran in persistent mode with the xplat
feature flags (for either variant).

As a result, invalid test gating like in
#29664 were not caught.

This PR adds test flavors for `ReactFeatureFlag-native-fb.js` in both
variants.
  • Loading branch information
rickhanlonii authored Jun 4, 2024
1 parent 9185b9b commit eabb681
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 144 deletions.
10 changes: 10 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ workflows:
- "-r=www-modern --env=production --variant=false"
- "-r=www-modern --env=development --variant=true"
- "-r=www-modern --env=production --variant=true"
- "-r=xplat --env=development --variant=false"
- "-r=xplat --env=development --variant=true"
- "-r=xplat --env=production --variant=false"
- "-r=xplat --env=production --variant=true"

# TODO: Test more persistent configurations?
- '-r=stable --env=development --persistent'
Expand Down Expand Up @@ -552,6 +556,12 @@ workflows:
# - "-r=www-modern --env=development --variant=true"
# - "-r=www-modern --env=production --variant=true"

# TODO: Update test config to support xplat build tests
# - "-r=xplat --env=development --variant=false"
# - "-r=xplat --env=development --variant=true"
# - "-r=xplat --env=production --variant=false"
# - "-r=xplat --env=production --variant=true"

# TODO: Test more persistent configurations?
- download_base_build_for_sizebot:
filters:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1377,113 +1377,118 @@ describe('ResponderEventPlugin', () => {
expect(ResponderEventPlugin._getResponder()).toBe(null);
});

it('should determine the first common ancestor correctly', async () => {
// This test was moved here from the ReactTreeTraversal test since only the
// ResponderEventPlugin uses `getLowestCommonAncestor`
const React = require('react');
const ReactDOMClient = require('react-dom/client');
const act = require('internal-test-utils').act;
const getLowestCommonAncestor =
require('react-native-renderer/src/legacy-events/ResponderEventPlugin').getLowestCommonAncestor;
// This works by accident and will likely break in the future.
const ReactDOMComponentTree = require('react-dom-bindings/src/client/ReactDOMComponentTree');

class ChildComponent extends React.Component {
divRef = React.createRef();
div1Ref = React.createRef();
div2Ref = React.createRef();

render() {
return (
<div ref={this.divRef} id={this.props.id + '__DIV'}>
<div ref={this.div1Ref} id={this.props.id + '__DIV_1'} />
<div ref={this.div2Ref} id={this.props.id + '__DIV_2'} />
</div>
);
it(
'should determine the first common ancestor correctly',
async () => {
// This test was moved here from the ReactTreeTraversal test since only the
// ResponderEventPlugin uses `getLowestCommonAncestor`
const React = require('react');
const ReactDOMClient = require('react-dom/client');
const act = require('internal-test-utils').act;
const getLowestCommonAncestor =
require('react-native-renderer/src/legacy-events/ResponderEventPlugin').getLowestCommonAncestor;
// This works by accident and will likely break in the future.
const ReactDOMComponentTree = require('react-dom-bindings/src/client/ReactDOMComponentTree');

class ChildComponent extends React.Component {
divRef = React.createRef();
div1Ref = React.createRef();
div2Ref = React.createRef();

render() {
return (
<div ref={this.divRef} id={this.props.id + '__DIV'}>
<div ref={this.div1Ref} id={this.props.id + '__DIV_1'} />
<div ref={this.div2Ref} id={this.props.id + '__DIV_2'} />
</div>
);
}
}
}

class ParentComponent extends React.Component {
pRef = React.createRef();
p_P1Ref = React.createRef();
p_P1_C1Ref = React.createRef();
p_P1_C2Ref = React.createRef();
p_OneOffRef = React.createRef();

render() {
return (
<div ref={this.pRef} id="P">
<div ref={this.p_P1Ref} id="P_P1">
<ChildComponent ref={this.p_P1_C1Ref} id="P_P1_C1" />
<ChildComponent ref={this.p_P1_C2Ref} id="P_P1_C2" />
class ParentComponent extends React.Component {
pRef = React.createRef();
p_P1Ref = React.createRef();
p_P1_C1Ref = React.createRef();
p_P1_C2Ref = React.createRef();
p_OneOffRef = React.createRef();

render() {
return (
<div ref={this.pRef} id="P">
<div ref={this.p_P1Ref} id="P_P1">
<ChildComponent ref={this.p_P1_C1Ref} id="P_P1_C1" />
<ChildComponent ref={this.p_P1_C2Ref} id="P_P1_C2" />
</div>
<div ref={this.p_OneOffRef} id="P_OneOff" />
</div>
<div ref={this.p_OneOffRef} id="P_OneOff" />
</div>
);
);
}
}
}

const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let parent;
await act(() => {
root.render(<ParentComponent ref={current => (parent = current)} />);
});

const ancestors = [
// Common ancestor with self is self.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.div1Ref.current,
com: parent.p_P1_C1Ref.current.div1Ref.current,
},
// Common ancestor with self is self - even if topmost DOM.
{
one: parent.pRef.current,
two: parent.pRef.current,
com: parent.pRef.current,
},
// Siblings
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.div2Ref.current,
com: parent.p_P1_C1Ref.current.divRef.current,
},
// Common ancestor with parent is the parent.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.divRef.current,
com: parent.p_P1_C1Ref.current.divRef.current,
},
// Common ancestor with grandparent is the grandparent.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1Ref.current,
com: parent.p_P1Ref.current,
},
// Grandparent across subcomponent boundaries.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C2Ref.current.div1Ref.current,
com: parent.p_P1Ref.current,
},
// Something deep with something one-off.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_OneOffRef.current,
com: parent.pRef.current,
},
];
let i;
for (i = 0; i < ancestors.length; i++) {
const plan = ancestors[i];
const firstCommon = getLowestCommonAncestor(
ReactDOMComponentTree.getInstanceFromNode(plan.one),
ReactDOMComponentTree.getInstanceFromNode(plan.two),
);
expect(firstCommon).toBe(
ReactDOMComponentTree.getInstanceFromNode(plan.com),
);
}
});
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let parent;
await act(() => {
root.render(<ParentComponent ref={current => (parent = current)} />);
});

const ancestors = [
// Common ancestor with self is self.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.div1Ref.current,
com: parent.p_P1_C1Ref.current.div1Ref.current,
},
// Common ancestor with self is self - even if topmost DOM.
{
one: parent.pRef.current,
two: parent.pRef.current,
com: parent.pRef.current,
},
// Siblings
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.div2Ref.current,
com: parent.p_P1_C1Ref.current.divRef.current,
},
// Common ancestor with parent is the parent.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C1Ref.current.divRef.current,
com: parent.p_P1_C1Ref.current.divRef.current,
},
// Common ancestor with grandparent is the grandparent.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1Ref.current,
com: parent.p_P1Ref.current,
},
// Grandparent across subcomponent boundaries.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_P1_C2Ref.current.div1Ref.current,
com: parent.p_P1Ref.current,
},
// Something deep with something one-off.
{
one: parent.p_P1_C1Ref.current.div1Ref.current,
two: parent.p_OneOffRef.current,
com: parent.pRef.current,
},
];
let i;
for (i = 0; i < ancestors.length; i++) {
const plan = ancestors[i];
const firstCommon = getLowestCommonAncestor(
ReactDOMComponentTree.getInstanceFromNode(plan.one),
ReactDOMComponentTree.getInstanceFromNode(plan.two),
);
expect(firstCommon).toBe(
ReactDOMComponentTree.getInstanceFromNode(plan.com),
);
}
},
// TODO: this is a long running test, we should speed it up.
60 * 1000,
);
});
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/__tests__/Activity-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('Activity', () => {
);
});

// @gate www && !disableLegacyMode
// @gate enableLegacyHidden && !disableLegacyMode
it('does not defer in legacy mode', async () => {
let setState;
function Foo() {
Expand Down Expand Up @@ -163,7 +163,7 @@ describe('Activity', () => {
);
});

// @gate www
// @gate enableLegacyHidden
it('does defer in concurrent mode', async () => {
let setState;
function Foo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ describe('Activity Suspense', () => {
);
});

// @gate www
// @gate enableLegacyHidden
test('LegacyHidden does not handle suspense', async () => {
const root = ReactNoop.createRoot();

Expand Down Expand Up @@ -174,7 +174,7 @@ describe('Activity Suspense', () => {
);
});

// @gate experimental || www
// @gate enableActivity
test("suspending inside currently hidden tree that's switching to visible", async () => {
const root = ReactNoop.createRoot();

Expand Down Expand Up @@ -319,7 +319,7 @@ describe('Activity Suspense', () => {
);
});

// @gate experimental || www
// @gate enableActivity
test('update that suspends inside hidden tree', async () => {
let setText;
function Child() {
Expand Down Expand Up @@ -352,7 +352,7 @@ describe('Activity Suspense', () => {
});
});

// @gate experimental || www
// @gate enableActivity
test('updates at multiple priorities that suspend inside hidden tree', async () => {
let setText;
let setStep;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ describe('ReactLazyContextPropagation', () => {
expect(root).toMatchRenderedOutput('BB');
});

// @gate www
// @gate enableLegacyCache && enableLegacyHidden
test('context is propagated through offscreen trees', async () => {
const LegacyHidden = React.unstable_LegacyHidden;

Expand Down Expand Up @@ -596,7 +596,7 @@ describe('ReactLazyContextPropagation', () => {
expect(root).toMatchRenderedOutput('BB');
});

// @gate www
// @gate enableLegacyCache && enableLegacyHidden
test('multiple contexts are propagated across through offscreen trees', async () => {
// Same as previous test, but with multiple context providers
const LegacyHidden = React.unstable_LegacyHidden;
Expand Down Expand Up @@ -822,7 +822,7 @@ describe('ReactLazyContextPropagation', () => {
expect(root).toMatchRenderedOutput('BB');
});

// @gate www
// @gate enableLegacyCache && enableLegacyHidden
test('nested bailouts through offscreen trees', async () => {
// Lazy context propagation will stop propagating when it hits the first
// match. If we bail out again inside that tree, we must resume propagating.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ describe('ReactIncremental', () => {
expect(inst.state).toEqual({text: 'bar', text2: 'baz'});
});

// @gate www
// @gate enableLegacyHidden
it('can deprioritize unfinished work and resume it later', async () => {
function Bar(props) {
Scheduler.log('Bar');
Expand Down Expand Up @@ -279,7 +279,7 @@ describe('ReactIncremental', () => {
await waitForAll(['Middle', 'Middle']);
});

// @gate www
// @gate enableLegacyHidden
it('can deprioritize a tree from without dropping work', async () => {
function Bar(props) {
Scheduler.log('Bar');
Expand Down Expand Up @@ -1864,8 +1864,7 @@ describe('ReactIncremental', () => {
]);
});

// @gate www
// @gate !disableLegacyContext
// @gate enableLegacyHidden && !disableLegacyContext
it('provides context when reusing work', async () => {
class Intl extends React.Component {
static childContextTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ describe('ReactIncrementalErrorHandling', () => {
);
});

// @gate www
// @gate enableLegacyHidden
it('does not include offscreen work when retrying after an error', async () => {
function App(props) {
if (props.isBroken) {
Expand Down
Loading

0 comments on commit eabb681

Please sign in to comment.