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.         // eslint-disable-next-line no-unused-vars
    
  36.         startTransition: _,
    
  37.         // eslint-disable-next-line no-unused-vars
    
  38.         useSyncExternalStore: __,
    
  39.         ...otherExports
    
  40.       } = jest.requireActual('react');
    
  41.       return otherExports;
    
  42.     });
    
  43. 
    
  44.     React = require('react');
    
  45.     ReactDOM = require('react-dom');
    
  46.     ReactDOMServer = require('react-dom/server');
    
  47.     Scheduler = require('scheduler');
    
  48. 
    
  49.     const InternalTestUtils = require('internal-test-utils');
    
  50.     assertLog = InternalTestUtils.assertLog;
    
  51. 
    
  52.     useSyncExternalStore =
    
  53.       require('use-sync-external-store/shim').useSyncExternalStore;
    
  54.   });
    
  55. 
    
  56.   function Text({text}) {
    
  57.     Scheduler.log(text);
    
  58.     return text;
    
  59.   }
    
  60. 
    
  61.   function createExternalStore(initialState) {
    
  62.     const listeners = new Set();
    
  63.     let currentState = initialState;
    
  64.     return {
    
  65.       set(text) {
    
  66.         currentState = text;
    
  67.         ReactDOM.unstable_batchedUpdates(() => {
    
  68.           listeners.forEach(listener => listener());
    
  69.         });
    
  70.       },
    
  71.       subscribe(listener) {
    
  72.         listeners.add(listener);
    
  73.         return () => listeners.delete(listener);
    
  74.       },
    
  75.       getState() {
    
  76.         return currentState;
    
  77.       },
    
  78.       getSubscriberCount() {
    
  79.         return listeners.size;
    
  80.       },
    
  81.     };
    
  82.   }
    
  83. 
    
  84.   test('basic server render', async () => {
    
  85.     const store = createExternalStore('client');
    
  86. 
    
  87.     function App() {
    
  88.       const text = useSyncExternalStore(
    
  89.         store.subscribe,
    
  90.         store.getState,
    
  91.         () => 'server',
    
  92.       );
    
  93.       return <Text text={text} />;
    
  94.     }
    
  95. 
    
  96.     const html = ReactDOMServer.renderToString(<App />);
    
  97. 
    
  98.     // We don't call getServerSnapshot in the shim
    
  99.     assertLog(['client']);
    
  100.     expect(html).toEqual('client');
    
  101.   });
    
  102. });