/** * Copyright (c) Meta Platforms, Inc. and 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 * @jest-environment node */ 'use strict'; let React; let ReactTestRenderer; let Scheduler; let waitForAll; let waitFor; describe('ReactTestRendererAsync', () => { beforeEach(() => { jest.resetModules(); React = require('react'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); const InternalTestUtils = require('internal-test-utils'); waitForAll = InternalTestUtils.waitForAll; waitFor = InternalTestUtils.waitFor; }); it('flushAll flushes all work', async () => { function Foo(props) { return props.children; } const renderer = ReactTestRenderer.create(Hi, { unstable_isConcurrent: true, }); // Before flushing, nothing has mounted. expect(renderer.toJSON()).toEqual(null); // Flush initial mount. await waitForAll([]); expect(renderer.toJSON()).toEqual('Hi'); // Update renderer.update(Bye); // Not yet updated. expect(renderer.toJSON()).toEqual('Hi'); // Flush update. await waitForAll([]); expect(renderer.toJSON()).toEqual('Bye'); }); it('flushAll returns array of yielded values', async () => { function Child(props) { Scheduler.log(props.children); return props.children; } function Parent(props) { return ( <> {'A:' + props.step} {'B:' + props.step} {'C:' + props.step} ); } const renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); await waitForAll(['A:1', 'B:1', 'C:1']); expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']); renderer.update(); await waitForAll(['A:2', 'B:2', 'C:2']); expect(renderer.toJSON()).toEqual(['A:2', 'B:2', 'C:2']); }); it('flushThrough flushes until the expected values is yielded', async () => { function Child(props) { Scheduler.log(props.children); return props.children; } function Parent(props) { return ( <> {'A:' + props.step} {'B:' + props.step} {'C:' + props.step} ); } let renderer; React.startTransition(() => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); }); // Flush the first two siblings await waitFor(['A:1', 'B:1']); // Did not commit yet. expect(renderer.toJSON()).toEqual(null); // Flush the remaining work await waitForAll(['C:1']); expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']); }); it('supports high priority interruptions', async () => { function Child(props) { Scheduler.log(props.children); return props.children; } class Example extends React.Component { componentDidMount() { expect(this.props.step).toEqual(2); } componentDidUpdate() { throw Error('Unexpected update'); } render() { return ( <> {'A:' + this.props.step} {'B:' + this.props.step} ); } } let renderer; React.startTransition(() => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); }); // Flush the some of the changes, but don't commit await waitFor(['A:1']); expect(renderer.toJSON()).toEqual(null); // Interrupt with higher priority properties renderer.unstable_flushSync(() => { renderer.update(); }); // Only the higher priority properties have been committed expect(renderer.toJSON()).toEqual(['A:2', 'B:2']); }); });