@samitouri / QOS-React / commits / 6a8a8ef326

[Flight] Add `<Activity>` (#34697)

Sebastian "Sebbie" Silbermann committed Oct 2, 2025 at 23:14 UTC 6a8a8ef32692cc42b53d072d5ce6a6a84e190482
6 files changed +140 -2
packages/react-reconciler/src/__tests__/ActivityReactServer-test.js new
+65
@@ -0,0 +1,65 @@
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 + * @emails react-core
8 + * @jest-environment node
9 + */
10 +
11 +'use strict';
12 +
13 +let act;
14 +let Activity;
15 +let React;
16 +let ReactServer;
17 +let ReactNoop;
18 +let ReactNoopFlightClient;
19 +let ReactNoopFlightServer;
20 +
21 +describe('ActivityReactServer', () => {
22 + beforeEach(() => {
23 + jest.resetModules();
24 + jest.mock('react', () => require('react/react.react-server'));
25 + ReactServer = require('react');
26 + Activity = ReactServer.Activity;
27 + ReactNoopFlightServer = require('react-noop-renderer/flight-server');
28 +
29 + jest.resetModules();
30 + __unmockReact();
31 + React = require('react');
32 + ReactNoopFlightClient = require('react-noop-renderer/flight-client');
33 + ReactNoop = require('react-noop-renderer');
34 + const InternalTestUtils = require('internal-test-utils');
35 + act = InternalTestUtils.act;
36 + });
37 +
38 + afterEach(() => {
39 + jest.restoreAllMocks();
40 + });
41 +
42 + it('can be rendered in React Server', async () => {
43 + function App() {
44 + return ReactServer.createElement(
45 + Activity,
46 + {mode: 'hidden'},
47 + ReactServer.createElement('div', null, 'Hello, Dave!'),
48 + );
49 + }
50 +
51 + const transport = ReactNoopFlightServer.render(
52 + ReactServer.createElement(App, null),
53 + );
54 +
55 + await act(async () => {
56 + const app = await ReactNoopFlightClient.read(transport);
57 +
58 + ReactNoop.render(app);
59 + });
60 +
61 + expect(ReactNoop).toMatchRenderedOutput(
62 + <div hidden={true}>Hello, Dave!</div>,
63 + );
64 + });
65 +});
packages/react-reconciler/src/__tests__/ViewTransitionReactServer-test.js new
+64
@@ -0,0 +1,64 @@
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 + * @emails react-core
8 + * @jest-environment node
9 + */
10 +
11 +'use strict';
12 +
13 +let act;
14 +let ViewTransition;
15 +let React;
16 +let ReactServer;
17 +let ReactNoop;
18 +let ReactNoopFlightClient;
19 +let ReactNoopFlightServer;
20 +
21 +describe('ViewTransitionReactServer', () => {
22 + beforeEach(() => {
23 + jest.resetModules();
24 + jest.mock('react', () => require('react/react.react-server'));
25 + ReactServer = require('react');
26 + ViewTransition = ReactServer.unstable_ViewTransition;
27 + ReactNoopFlightServer = require('react-noop-renderer/flight-server');
28 +
29 + jest.resetModules();
30 + __unmockReact();
31 + React = require('react');
32 + ReactNoopFlightClient = require('react-noop-renderer/flight-client');
33 + ReactNoop = require('react-noop-renderer');
34 + const InternalTestUtils = require('internal-test-utils');
35 + act = InternalTestUtils.act;
36 + });
37 +
38 + afterEach(() => {
39 + jest.restoreAllMocks();
40 + });
41 +
42 + // @gate enableViewTransition || fb
43 + it('can be rendered in React Server', async () => {
44 + function App() {
45 + return ReactServer.createElement(
46 + ViewTransition,
47 + {},
48 + ReactServer.createElement('div', null, 'Hello, Dave!'),
49 + );
50 + }
51 +
52 + const transport = ReactNoopFlightServer.render(
53 + ReactServer.createElement(App, null),
54 + );
55 +
56 + await act(async () => {
57 + const app = await ReactNoopFlightClient.read(transport);
58 +
59 + ReactNoop.render(app);
60 + });
61 +
62 + expect(ReactNoop).toMatchRenderedOutput(<div>Hello, Dave!</div>);
63 + });
64 +});
packages/react/src/ReactServer.experimental.development.js
+1 -1
@@ -58,6 +58,7 @@ export {
58
59 export {
60 Children,
61 + REACT_ACTIVITY_TYPE as Activity,
62 REACT_FRAGMENT_TYPE as Fragment,
63 REACT_PROFILER_TYPE as Profiler,
64 REACT_STRICT_MODE_TYPE as StrictMode,
@@ -83,6 +84,5 @@ export {
84 // Experimental
85 REACT_SUSPENSE_LIST_TYPE as unstable_SuspenseList,
86 REACT_VIEW_TRANSITION_TYPE as unstable_ViewTransition,
86 - REACT_ACTIVITY_TYPE as unstable_Activity,
87 captureOwnerStack, // DEV-only
88 };
packages/react/src/ReactServer.experimental.js
+1 -1
@@ -57,6 +57,7 @@ export {
57
58 export {
59 Children,
60 + REACT_ACTIVITY_TYPE as Activity,
61 REACT_FRAGMENT_TYPE as Fragment,
62 REACT_PROFILER_TYPE as Profiler,
63 REACT_STRICT_MODE_TYPE as StrictMode,
@@ -82,5 +83,4 @@ export {
83 // Experimental
84 REACT_SUSPENSE_LIST_TYPE as unstable_SuspenseList,
85 REACT_VIEW_TRANSITION_TYPE as unstable_ViewTransition,
85 - REACT_ACTIVITY_TYPE as Activity,
86 };
packages/react/src/ReactServer.fb.js
+7
@@ -12,10 +12,13 @@ export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRA
12 import {forEach, map, count, toArray, only} from './ReactChildren';
13 import {captureOwnerStack as captureOwnerStackImpl} from './ReactOwnerStack';
14 import {
15 + REACT_ACTIVITY_TYPE,
16 REACT_FRAGMENT_TYPE,
17 REACT_PROFILER_TYPE,
18 REACT_STRICT_MODE_TYPE,
19 REACT_SUSPENSE_TYPE,
20 + REACT_SUSPENSE_LIST_TYPE,
21 + REACT_VIEW_TRANSITION_TYPE,
22 } from 'shared/ReactSymbols';
23 import {
24 cloneElement,
@@ -45,6 +48,7 @@ if (__DEV__) {
48
49 export {
50 Children,
51 + REACT_ACTIVITY_TYPE as Activity,
52 REACT_FRAGMENT_TYPE as Fragment,
53 REACT_PROFILER_TYPE as Profiler,
54 REACT_STRICT_MODE_TYPE as StrictMode,
@@ -65,4 +69,7 @@ export {
69 useMemo,
70 version,
71 captureOwnerStack, // DEV-only
72 + // Experimental
73 + REACT_SUSPENSE_LIST_TYPE as unstable_SuspenseList,
74 + REACT_VIEW_TRANSITION_TYPE as unstable_ViewTransition,
75 };
packages/react/src/ReactServer.js
+2
@@ -11,6 +11,7 @@ export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRA
11
12 import {forEach, map, count, toArray, only} from './ReactChildren';
13 import {
14 + REACT_ACTIVITY_TYPE,
15 REACT_FRAGMENT_TYPE,
16 REACT_PROFILER_TYPE,
17 REACT_STRICT_MODE_TYPE,
@@ -40,6 +41,7 @@ const Children = {
41
42 export {
43 Children,
44 + REACT_ACTIVITY_TYPE as Activity,
45 REACT_FRAGMENT_TYPE as Fragment,
46 REACT_PROFILER_TYPE as Profiler,
47 REACT_STRICT_MODE_TYPE as StrictMode,