Repository: facebook/react
File: packages/internal-test-utils/internalAct.js (JavaScript)

Code before:
  }
}

async function waitForTasksAndTimers(error: mixed) {
  do {
    // Wait until end of current task/microtask.
    await waitForMicrotasks();

    // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    if (jest.isEnvironmentTornDown()) {
      error.message =
        'The Jest environment was torn down before `act` completed. This ' +
        'probably means you forgot to `await` an `act` call.';
      throw error;
    }

    // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    const j = jest;
    if (j.getTimerCount() > 0) {
      // There's a pending timer. Flush it now. We only do this in order to
      // force Suspense fallbacks to display; the fact that it's a timer
      // is an implementation detail. If there are other timers scheduled,
      // those will also fire now, too, which is not ideal. (The public
      // version of `act` doesn't do this.) For this reason, we should try
      // to avoid using timers in our internal tests.
      j.runAllTicks();
      j.runOnlyPendingTimers();
      // If a committing a fallback triggers another update, it might not
      // get scheduled until a microtask. So wait one more time.
      await waitForMicrotasks();
    } else {
      break;
    }
  } while (true);
}

export async function serverAct<T>(scope: () => Thenable<T>): Thenable<T> {
  // We require every `act` call to assert console logs
  // with one of the assertion helpers. Fails if not empty.
  assertConsoleLogsCleared();

  // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
  if (!jest.isMockFunction(setTimeout)) {
    throw Error(
      "This version of `act` requires Jest's timer mocks " +
        '(i.e. jest.useFakeTimers).',
    );
  }

  // Create the error object before doing any async work, to get a better
  // stack trace.

Review comment (bug):
`getTimerCount()` includes `process.nextTick` mocks but `runOnlyPendingTimers()` alone doesn't run them. We don't use it ourselves but JSDOM uses it internally. This was driving me insane debugging this infinite loop.

Code after:
  }
}

async function waitForTasksAndTimers(error: Error) {
  do {
    // Wait until end of current task/microtask.
    await waitForMicrotasks();

    // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    if (jest.isEnvironmentTornDown()) {
      error.message =
        'The Jest environment was torn down before `act` completed. This ' +
        'probably means you forgot to `await` an `act` call.';
      throw error;
    }

    // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    const j = jest;
    if (j.getTimerCount() > 0) {
      // There's a pending timer. Flush it now. We only do this in order to
      // force Suspense fallbacks to display; the fact that it's a timer
      // is an implementation detail. If there are other timers scheduled,
      // those will also fire now, too, which is not ideal. (The public
      // version of `act` doesn't do this.) For this reason, we should try
      // to avoid using timers in our internal tests.
      j.runAllTicks();
      j.runOnlyPendingTimers();
      // If a committing a fallback triggers another update, it might not
      // get scheduled until a microtask. So wait one more time.
      await waitForMicrotasks();
    } else {
      break;
    }
  } while (true);
}

export async function serverAct<T>(scope: () => Thenable<T>): Thenable<T> {
  // We require every `act` call to assert console logs
  // with one of the assertion helpers. Fails if not empty.
  assertConsoleLogsCleared();

  // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
  if (!jest.isMockFunction(setTimeout)) {
    throw Error(
      "This version of `act` requires Jest's timer mocks " +
        '(i.e. jest.useFakeTimers).',
    );
  }

  // Create the error object before doing any async work, to get a better
  // stack trace.