@samitouri / QOS-React-1 / commits / 087a34696f

[test] add activity test with gSBU and enableViewTransition bugfix (#35555)

Related to https://github.com/facebook/react/pull/35548, `enableViewTransition` fixes a bug where `getSnapshotBeforeUpdate` was running in hidden trees when it shouldn't (`componentWillUpdate` won't run for hidden updates, and when it becomes visible it will be called with `componentWillMount`).

Ricky committed Feb 4, 2026 at 14:37 UTC 087a34696f1eb484157b19aee1648bcbce51de64
1 file changed +81
packages/react-reconciler/src/__tests__/Activity-test.js
+81
@@ -1527,6 +1527,87 @@ describe('Activity', () => {
1527 expect(root).toMatchRenderedOutput(<span prop={2} />);
1528 });
1529
1530 + // @gate enableActivity
1531 + it('getSnapshotBeforeUpdate does not run in hidden trees', async () => {
1532 + let setState;
1533 +
1534 + class Child extends React.Component {
1535 + getSnapshotBeforeUpdate(prevProps) {
1536 + const snapshot = `snapshot-${prevProps.value}-to-${this.props.value}`;
1537 + Scheduler.log(`getSnapshotBeforeUpdate: ${snapshot}`);
1538 + return snapshot;
1539 + }
1540 + componentDidUpdate(prevProps, prevState, snapshot) {
1541 + Scheduler.log(`componentDidUpdate: ${snapshot}`);
1542 + }
1543 + componentDidMount() {
1544 + Scheduler.log('componentDidMount');
1545 + }
1546 + componentWillUnmount() {
1547 + Scheduler.log('componentWillUnmount');
1548 + }
1549 + render() {
1550 + Scheduler.log(`render: ${this.props.value}`);
1551 + return <span prop={this.props.value} />;
1552 + }
1553 + }
1554 +
1555 + function Wrapper({show}) {
1556 + const [value, _setState] = useState(1);
1557 + setState = _setState;
1558 + return (
1559 + <Activity mode={show ? 'visible' : 'hidden'}>
1560 + <Child value={value} />
1561 + </Activity>
1562 + );
1563 + }
1564 +
1565 + const root = ReactNoop.createRoot();
1566 +
1567 + // Initial render
1568 + await act(() => {
1569 + root.render(<Wrapper show={true} />);
1570 + });
1571 + assertLog(['render: 1', 'componentDidMount']);
1572 +
1573 + // Hide the Activity
1574 + await act(() => {
1575 + root.render(<Wrapper show={false} />);
1576 + });
1577 + assertLog([
1578 + 'componentWillUnmount',
1579 + 'render: 1',
1580 + // Bugfix: snapshots for hidden trees should not need to be read.
1581 + ...(gate('enableViewTransition')
1582 + ? []
1583 + : ['getSnapshotBeforeUpdate: snapshot-1-to-1']),
1584 + ]);
1585 +
1586 + // Trigger an update while hidden by calling setState
1587 + await act(() => {
1588 + setState(2);
1589 + });
1590 + assertLog([
1591 + 'render: 2',
1592 + ...(gate('enableViewTransition')
1593 + ? []
1594 + : ['getSnapshotBeforeUpdate: snapshot-1-to-2']),
1595 + ]);
1596 +
1597 + // This is treated as a new mount so the snapshot also shouldn't be read.
1598 + await act(() => {
1599 + root.render(<Wrapper show={true} />);
1600 + });
1601 + assertLog([
1602 + 'render: 2',
1603 + ...(gate('enableViewTransition')
1604 + ? []
1605 + : ['getSnapshotBeforeUpdate: snapshot-2-to-2']),
1606 + 'componentDidMount',
1607 + ]);
1608 + });
1609 +
1610 + // @gate enableActivity
1611 it('warns if you pass a hidden prop', async () => {
1612 function App() {
1613 return (