main
js 100 lines 2.52 KB
Raw
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 *
9 * @jest-environment node
10 */
11
12 'use strict';
13
14 let useSyncExternalStore;
15 let React;
16 let ReactDOM;
17 let ReactDOMServer;
18 let Scheduler;
19 let assertLog;
20
21 // This tests the userspace shim of `useSyncExternalStore` in a server-rendering
22 // (Node) environment
23 describe('useSyncExternalStore (userspace shim, server rendering)', () => {
24 beforeEach(() => {
25 jest.resetModules();
26
27 // Remove useSyncExternalStore from the React imports so that we use the
28 // shim instead. Also removing startTransition, since we use that to detect
29 // outdated 18 alphas that don't yet include useSyncExternalStore.
30 //
31 // Longer term, we'll probably test this branch using an actual build of
32 // React 17.
33 jest.mock('react', () => {
34 const {
35 startTransition: _,
36 useSyncExternalStore: __,
37 ...otherExports
38 } = jest.requireActual('react');
39 return otherExports;
40 });
41
42 React = require('react');
43 ReactDOM = require('react-dom');
44 ReactDOMServer = require('react-dom/server');
45 Scheduler = require('scheduler');
46
47 const InternalTestUtils = require('internal-test-utils');
48 assertLog = InternalTestUtils.assertLog;
49
50 useSyncExternalStore =
51 require('use-sync-external-store/shim').useSyncExternalStore;
52 });
53
54 function Text({text}) {
55 Scheduler.log(text);
56 return text;
57 }
58
59 function createExternalStore(initialState) {
60 const listeners = new Set();
61 let currentState = initialState;
62 return {
63 set(text) {
64 currentState = text;
65 ReactDOM.unstable_batchedUpdates(() => {
66 listeners.forEach(listener => listener());
67 });
68 },
69 subscribe(listener) {
70 listeners.add(listener);
71 return () => listeners.delete(listener);
72 },
73 getState() {
74 return currentState;
75 },
76 getSubscriberCount() {
77 return listeners.size;
78 },
79 };
80 }
81
82 it('basic server render', async () => {
83 const store = createExternalStore('client');
84
85 function App() {
86 const text = useSyncExternalStore(
87 store.subscribe,
88 store.getState,
89 () => 'server',
90 );
91 return <Text text={text} />;
92 }
93
94 const html = ReactDOMServer.renderToString(<App />);
95
96 // We don't call getServerSnapshot in the shim
97 assertLog(['client']);
98 expect(html).toEqual('client');
99 });
100 });