[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,