text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @emails react-core
   */
  
  'use strict';
  
  const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
  
  let React;
  let ReactDOM;
  let ReactDOMServer;
  let ReactTestUtils;
  
  function initModules() {
    // Reset warning cache.
    jest.resetModuleRegistry();
    React = require('react');
    ReactDOM = require('react-dom');
    ReactDOMServer = require('react-dom/server');
    ReactTestUtils = require('react-dom/test-utils');
  
    // Make them available to the helpers.
    return {
      ReactDOM,
      ReactDOMServer,
      ReactTestUtils,
    };
  }
  
  const {resetModules, itRenders} = ReactDOMServerIntegrationUtils(initModules);
  
  describe('ReactDOMServerIntegration', () => {
    beforeEach(() => {
      resetModules();
    });
  
    describe('context', function() {
      let Context, PurpleContextProvider, RedContextProvider, Consumer;
      beforeEach(() => {
        Context = React.createContext('none');
  
        class Parent extends React.Component {
          render() {
            return (
              <Context.Provider value={this.props.text}>
                {this.props.children}
              </Context.Provider>
            );
          }
        }
        Consumer = Context.Consumer;
        PurpleContextProvider = props => (
          <Parent text="purple">{props.children}</Parent>
        );
        RedContextProvider = props => (
          <Parent text="red">{props.children}</Parent>
        );
      });
  
      itRenders('class child with context', async render => {
        class ClassChildWithContext extends React.Component {
          render() {
            return (
              <div>
                <Consumer>{text => text}</Consumer>
              </div>
            );
          }
        }
  
        const e = await render(
          <PurpleContextProvider>
            <ClassChildWithContext />
          </PurpleContextProvider>,
        );
        expect(e.textContent).toBe('purple');
      });
  
      itRenders('stateless child with context', async render => {
        function FunctionChildWithContext(props) {
          return <Consumer>{text => text}</Consumer>;
        }
  
        const e = await render(
          <PurpleContextProvider>
            <FunctionChildWithContext />
          </PurpleContextProvider>,
        );
        expect(e.textContent).toBe('purple');
      });
  
      itRenders('class child with default context', async render => {
        class ClassChildWithWrongContext extends React.Component {
          render() {
            return (
              <div id="classWrongChild">
                <Consumer>{text => text}</Consumer>
              </div>
            );
          }
        }
  
        const e = await render(<ClassChildWithWrongContext />);
        expect(e.textContent).toBe('none');
      });
  
      itRenders('stateless child with wrong context', async render => {
        function FunctionChildWithWrongContext(props) {
          return (
            <div id="statelessWrongChild">
              <Consumer>{text => text}</Consumer>
            </div>
          );
        }
  
        const e = await render(<FunctionChildWithWrongContext />);
        expect(e.textContent).toBe('none');
      });
  
      itRenders('with context passed through to a grandchild', async render => {
        function Grandchild(props) {
          return (
            <div>
              <Consumer>{text => text}</Consumer>
            </div>
          );
        }
  
        const Child = props => <Grandchild />;
  
        const e = await render(
          <PurpleContextProvider>
            <Child />
          </PurpleContextProvider>,
        );
        expect(e.textContent).toBe('purple');
      });
  
      itRenders('a child context overriding a parent context', async render => {
        const Grandchild = props => {
          return (
            <div>
              <Consumer>{text => text}</Consumer>
            </div>
          );
        };
  
        const e = await render(
          <PurpleContextProvider>
            <RedContextProvider>
              <Grandchild />
            </RedContextProvider>
          </PurpleContextProvider>,
        );
        expect(e.textContent).toBe('red');
      });
  
      itRenders('readContext() in different components', async render => {
        function readContext(Ctx, observedBits) {
          const dispatcher =
            React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
              .ReactCurrentDispatcher.current;
          return dispatcher.readContext(Ctx, observedBits);
        }
  
        class Cls extends React.Component {
          render() {
            return readContext(Context);
          }
        }
        function Fn() {
          return readContext(Context);
        }
        const Memo = React.memo(() => {
          return readContext(Context);
        });
        const FwdRef = React.forwardRef((props, ref) => {
          return readContext(Context);
        });
  
        const e = await render(
          <PurpleContextProvider>
            <RedContextProvider>
              <span>
                <Fn />
                <Cls />
                <Memo />
                <FwdRef />
                <Consumer>{() => readContext(Context)}</Consumer>
              </span>
            </RedContextProvider>
          </PurpleContextProvider>,
        );
        expect(e.textContent).toBe('redredredredred');
      });
  
      itRenders('multiple contexts', async render => {
        const Theme = React.createContext('dark');
        const Language = React.createContext('french');
        class Parent extends React.Component {
          render() {
            return (
              <Theme.Provider value="light">
                <Child />
              </Theme.Provider>
            );
          }
        }
  
        function Child() {
          return (
            <Language.Provider value="english">
              <Grandchild />
            </Language.Provider>
          );
        }
  
        const Grandchild = props => {
          return (
            <div>
              <Theme.Consumer>
                {theme => <div id="theme">{theme}</div>}
              </Theme.Consumer>
              <Language.Consumer>
                {language => <div id="language">{language}</div>}
              </Language.Consumer>
            </div>
          );
        };
  
        const e = await render(<Parent />);
        expect(e.querySelector('#theme').textContent).toBe('light');
        expect(e.querySelector('#language').textContent).toBe('english');
      });
  
      itRenders('nested context unwinding', async render => {
        const Theme = React.createContext('dark');
        const Language = React.createContext('french');
  
        const App = () => (
          <div>
            <Theme.Provider value="light">
              <Language.Provider value="english">
                <Theme.Provider value="dark">
                  <Theme.Consumer>
                    {theme => <div id="theme1">{theme}</div>}
                  </Theme.Consumer>
                </Theme.Provider>
                <Theme.Consumer>
                  {theme => <div id="theme2">{theme}</div>}
                </Theme.Consumer>
                <Language.Provider value="sanskrit">
                  <Theme.Provider value="blue">
                    <Theme.Provider value="red">
                      <Language.Consumer>
                        {() => (
                          <Language.Provider value="chinese">
                            <Language.Provider value="hungarian" />
                            <Language.Consumer>
                              {language => <div id="language1">{language}</div>}
                            </Language.Consumer>
                          </Language.Provider>
                        )}
                      </Language.Consumer>
                    </Theme.Provider>
                    <Language.Consumer>
                      {language => (
                        <>
                          <Theme.Consumer>
                            {theme => <div id="theme3">{theme}</div>}
                          </Theme.Consumer>
                          <div id="language2">{language}</div>
                        </>
                      )}
                    </Language.Consumer>
                  </Theme.Provider>
                </Language.Provider>
              </Language.Provider>
            </Theme.Provider>
            <Language.Consumer>
              {language => <div id="language3">{language}</div>}
            </Language.Consumer>
          </div>
        );
        const e = await render(<App />);
        expect(e.querySelector('#theme1').textContent).toBe('dark');
        expect(e.querySelector('#theme2').textContent).toBe('light');
        expect(e.querySelector('#theme3').textContent).toBe('blue');
        expect(e.querySelector('#language1').textContent).toBe('chinese');
        expect(e.querySelector('#language2').textContent).toBe('sanskrit');
        expect(e.querySelector('#language3').textContent).toBe('french');
      });
  
      itRenders(
        'should warn with an error message when using Context as consumer in DEV',
        async render => {
          const Theme = React.createContext('dark');
          const Language = React.createContext('french');
  
          const App = () => (
            <div>
              <Theme.Provider value="light">
                <Language.Provider value="english">
                  <Theme.Provider value="dark">
                    <Theme>{theme => <div id="theme1">{theme}</div>}</Theme>
                  </Theme.Provider>
                </Language.Provider>
              </Theme.Provider>
            </div>
          );
          // We expect 1 error.
          await render(<App />, 1);
        },
      );
  
      // False positive regression test.
      itRenders(
        'should not warn when using Consumer from React < 16.6 with newer renderer',
        async render => {
          const Theme = React.createContext('dark');
          const Language = React.createContext('french');
          // React 16.5 and earlier didn't have a separate object.
          Theme.Consumer = Theme;
  
          const App = () => (
            <div>
              <Theme.Provider value="light">
                <Language.Provider value="english">
                  <Theme.Provider value="dark">
                    <Theme>{theme => <div id="theme1">{theme}</div>}</Theme>
                  </Theme.Provider>
                </Language.Provider>
              </Theme.Provider>
            </div>
          );
          // We expect 0 errors.
          await render(<App />, 0);
        },
      );
  
      itRenders(
        'should warn with an error message when using nested context consumers in DEV',
        async render => {
          const App = () => {
            const Theme = React.createContext('dark');
            const Language = React.createContext('french');
  
            return (
              <div>
                <Theme.Provider value="light">
                  <Language.Provider value="english">
                    <Theme.Provider value="dark">
                      <Theme.Consumer.Consumer>
                        {theme => <div id="theme1">{theme}</div>}
                      </Theme.Consumer.Consumer>
                    </Theme.Provider>
                  </Language.Provider>
                </Theme.Provider>
              </div>
            );
          };
          // We expect 1 error.
          await render(<App />, 1);
        },
      );
  
      itRenders(
        'should warn with an error message when using Context.Consumer.Provider DEV',
        async render => {
          const App = () => {
            const Theme = React.createContext('dark');
            const Language = React.createContext('french');
  
            return (
              <div>
                <Theme.Provider value="light">
                  <Language.Provider value="english">
                    <Theme.Consumer.Provider value="dark">
                      <Theme.Consumer>
                        {theme => <div id="theme1">{theme}</div>}
                      </Theme.Consumer>
                    </Theme.Consumer.Provider>
                  </Language.Provider>
                </Theme.Provider>
              </div>
            );
          };
          // We expect 1 error.
          await render(<App />, 1);
        },
      );
  
      it('does not pollute parallel node streams', () => {
        const LoggedInUser = React.createContext();
  
        const AppWithUser = user => (
          <LoggedInUser.Provider value={user}>
            <header>
              <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
            </header>
            <footer>
              <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
            </footer>
          </LoggedInUser.Provider>
        );
  
        const streamAmy = ReactDOMServer.renderToNodeStream(
          AppWithUser('Amy'),
        ).setEncoding('utf8');
        const streamBob = ReactDOMServer.renderToNodeStream(
          AppWithUser('Bob'),
        ).setEncoding('utf8');
  
        // Testing by filling the buffer using internal _read() with a small
        // number of bytes to avoid a test case which needs to align to a
        // highWaterMark boundary of 2^14 chars.
        streamAmy._read(20);
        streamBob._read(20);
        streamAmy._read(20);
        streamBob._read(20);
  
        expect(streamAmy.read()).toBe('<header>Amy</header><footer>Amy</footer>');
        expect(streamBob.read()).toBe('<header>Bob</header><footer>Bob</footer>');
      });
  
      it('does not pollute parallel node streams when many are used', () => {
        const CurrentIndex = React.createContext();
  
        const NthRender = index => (
          <CurrentIndex.Provider value={index}>
            <header>
              <CurrentIndex.Consumer>{idx => idx}</CurrentIndex.Consumer>
            </header>
            <footer>
              <CurrentIndex.Consumer>{idx => idx}</CurrentIndex.Consumer>
            </footer>
          </CurrentIndex.Provider>
        );
  
        const streams = [];
  
        // Test with more than 32 streams to test that growing the thread count
        // works properly.
        const streamCount = 34;
  
        for (let i = 0; i < streamCount; i++) {
          streams[i] = ReactDOMServer.renderToNodeStream(
            NthRender(i % 2 === 0 ? 'Expected to be recreated' : i),
          ).setEncoding('utf8');
        }
  
        // Testing by filling the buffer using internal _read() with a small
        // number of bytes to avoid a test case which needs to align to a
        // highWaterMark boundary of 2^14 chars.
        for (let i = 0; i < streamCount; i++) {
          streams[i]._read(20);
        }
  
        // Early destroy every other stream
        for (let i = 0; i < streamCount; i += 2) {
          streams[i].destroy();
        }
  
        // Recreate those same streams.
        for (let i = 0; i < streamCount; i += 2) {
          streams[i] = ReactDOMServer.renderToNodeStream(
            NthRender(i),
          ).setEncoding('utf8');
        }
  
        // Read a bit from all streams again.
        for (let i = 0; i < streamCount; i++) {
          streams[i]._read(20);
        }
  
        // Assert that all stream rendered the expected output.
        for (let i = 0; i < streamCount; i++) {
          expect(streams[i].read()).toBe(
            '<header>' + i + '</header><footer>' + i + '</footer>',
          );
        }
      });
  
      // Regression test for https://github.com/facebook/react/issues/14705
      it('does not pollute later renders when stream destroyed', () => {
        const LoggedInUser = React.createContext('default');
  
        const AppWithUser = user => (
          <LoggedInUser.Provider value={user}>
            <header>
              <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
            </header>
          </LoggedInUser.Provider>
        );
  
        const stream = ReactDOMServer.renderToNodeStream(
          AppWithUser('Amy'),
        ).setEncoding('utf8');
  
        // This is an implementation detail because we test a memory leak
        const {threadID} = stream.partialRenderer;
  
        // Read enough to render Provider but not enough for it to be exited
        stream._read(10);
        expect(LoggedInUser[threadID]).toBe('Amy');
  
        stream.destroy();
  
        const AppWithUserNoProvider = () => (
          <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
        );
  
        const stream2 = ReactDOMServer.renderToNodeStream(
          AppWithUserNoProvider(),
        ).setEncoding('utf8');
  
        // Sanity check to ensure 2nd render has same threadID as 1st render,
        // otherwise this test is not testing what it's meant to
        expect(stream2.partialRenderer.threadID).toBe(threadID);
  
        const markup = stream2.read(Infinity);
  
        expect(markup).toBe('default');
      });
  
      // Regression test for https://github.com/facebook/react/issues/14705
      it('frees context value reference when stream destroyed', () => {
        const LoggedInUser = React.createContext('default');
  
        const AppWithUser = user => (
          <LoggedInUser.Provider value={user}>
            <header>
              <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
            </header>
          </LoggedInUser.Provider>
        );
  
        const stream = ReactDOMServer.renderToNodeStream(
          AppWithUser('Amy'),
        ).setEncoding('utf8');
  
        // This is an implementation detail because we test a memory leak
        const {threadID} = stream.partialRenderer;
  
        // Read enough to render Provider but not enough for it to be exited
        stream._read(10);
        expect(LoggedInUser[threadID]).toBe('Amy');
  
        stream.destroy();
        expect(LoggedInUser[threadID]).toBe('default');
      });
  
      it('does not pollute sync renders after an error', () => {
        const LoggedInUser = React.createContext('default');
        const Crash = () => {
          throw new Error('Boo!');
        };
        const AppWithUser = user => (
          <LoggedInUser.Provider value={user}>
            <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>
            <Crash />
          </LoggedInUser.Provider>
        );
  
        expect(() => {
          ReactDOMServer.renderToString(AppWithUser('Casper'));
        }).toThrow('Boo');
  
        // Should not report a value from failed render
        expect(
          ReactDOMServer.renderToString(
            <LoggedInUser.Consumer>{whoAmI => whoAmI}</LoggedInUser.Consumer>,
          ),
        ).toBe('default');
      });
    });
  });
  