Repository: facebook/react
File: packages/react-reconciler/src/__tests__/ReactFlushSync-test.js (JavaScript)

Code before:
    }

    const root = ReactNoop.createRoot();
    await act(() => {
      root.render(<App />);
    });
    assertLog(['0, 0']);
    expect(root).toMatchRenderedOutput('0, 0');

    await act(() => {
      ReactNoop.flushSync(() => {
        startTransition(() => {
          // This should be async even though flushSync is on the stack, because
          // startTransition is closer.
          setState(1);
          ReactNoop.flushSync(() => {
            // This should be async even though startTransition is on the stack,
            // because flushSync is closer.
            setSyncState(1);
          });
        });
      });
      // Only the sync update should have flushed
      assertLog(['1, 0']);
      expect(root).toMatchRenderedOutput('1, 0');
    });
    // Now the async update has flushed, too.
    assertLog(['1, 1']);
    expect(root).toMatchRenderedOutput('1, 1');
  });

  test('flushes passive effects synchronously when they are the result of a sync render', async () => {
    function App() {
      useEffect(() => {
        Scheduler.log('Effect');
      }, []);
      return <Text text="Child" />;
    }

    const root = ReactNoop.createRoot();
    await act(() => {
      ReactNoop.flushSync(() => {
        root.render(<App />);
      });
      assertLog([
        'Child',
        // Because the pending effect was the result of a sync update, calling
        // flushSync should flush it.
        'Effect',
      ]);
      expect(root).toMatchRenderedOutput('Child');

Review comment (refactor):
What do you think about creating a matcher for this? Seems common and we're starting to copy this helper over to multiple places. It would be nice to standardize the ReactDOM tests asserting container content on one patter because it's all over the place right now

Code after:
    const root = ReactDOMClient.createRoot(container);
    await act(async () => {
      React.startTransition(() => {
        root.render(<App />);
      });
      // This will yield right before the passive effect fires
      await waitForPaint(['0, 0']);

      // The passive effect will schedule a sync update and a normal update.
      // They should commit in two separate batches. First the sync one.
      await waitForPaint(
        gate(flags => flags.enableUnifiedSyncLane) ? ['1, 1'] : ['1, 0'],
      );

      // The remaining update is not sync
      ReactDOM.flushSync();
      assertLog([]);

      if (gate(flags => flags.enableUnifiedSyncLane)) {
        await waitForPaint([]);
      } else {
        // Now flush it.
        await waitForPaint(['1, 1']);
      }
    });
    expect(getVisibleChildren(container)).toEqual('1, 1');

    if (__DEV__) {
      expect(console.error.mock.calls[0][0]).toContain(
        'flushSync was called from inside a lifecycle method. React ' +
          'cannot flush when React is already rendering. Consider moving this ' +
          'call to a scheduler task or micro task.%s',
      );
    }
  });

  it('supports nested flushSync with startTransition', async () => {
    let setSyncState;
    let setState;
    function App() {
      const [syncState, _setSyncState] = useState(0);
      const [state, _setState] = useState(0);
      setSyncState = _setSyncState;
      setState = _setState;
      return <Text text={`${syncState}, ${state}`} />;
    }

    const container = document.createElement('div');
    const root = ReactDOMClient.createRoot(container);
    await act(() => {
      root.render(<App />);