Skip to content

Conversation

eps1lon
Copy link
Collaborator

@eps1lon eps1lon commented Aug 5, 2025

Summary

This includes the callsite of the act call for the following warnings:

  1. A component suspended inside an actscope, but theact call was not awaited. [...]
  2. You seem to have overlapping act() calls [...]
  3. You called act(async () => ...) without await.

All of these warnings require action at the callsite of the act so a stack is important to quickly identify where you need to adjust code.

Before (no clue where the issue is):

console.error
    A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:
    
    await act(() => ...)

      at ../node_modules/.pnpm/react@19.2.0-canary-c260b38d-20250731/node_modules/react/cjs/react.development.js:867:23
      at invokeTheCallbackFunction (../node_modules/.pnpm/jsdom@20.0.3/node_modules/jsdom/lib/jsdom/living/generated/Function.js:19:26)
      at ../node_modules/.pnpm/jsdom@20.0.3/node_modules/jsdom/lib/jsdom/browser/Window.js:554:9

After (the clue is in the stacktrace):

console.error
    Error: A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:
    
    await act(() => ...)
        at ~/node_modules/@testing-library/react/dist/act-compat.js:47:25
        at renderRoot (~/node_modules/@testing-library/react/dist/pure.js:180:26)
        at render (~/node_modules/@testing-library/react/dist/pure.js:271:10)
        at Object.<anonymous> (~/test/production/jest/rsc/app/client-component.test.jsx:13:9)

Test frameworks should implement ignore-listing in error inspection to clean up these stacktraces e.g. like Next.js does

How these warnings look in our internal test suite now

It's quite noisy but better than having no stacks. We can look into sourcemapping these stacks and apply ignore-lists if this becomes an issue.

console.error was called without assertConsoleErrorDev:
    + Error: A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:
    +
    + await act(() => ...)
    +     at /Users/sebbie/repos/react/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js:476:7
    +     at withActEnvironment (/Users/sebbie/repos/react/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js:151:20)
    +     at Object.<anonymous> (/Users/sebbie/repos/react/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js:473:11)
    +     at Promise.then.completed (/Users/sebbie/repos/react/node_modules/jest-circus/build/utils.js:298:28)
    +     at new Promise (<anonymous>)
    +     at callAsyncCircusFn (/Users/sebbie/repos/react/node_modules/jest-circus/build/utils.js:231:10)
    +     at _callCircusTest (/Users/sebbie/repos/react/node_modules/jest-circus/build/run.js:316:40)
    +     at _runTest (/Users/sebbie/repos/react/node_modules/jest-circus/build/run.js:252:3)
    +     at _runTestsForDescribeBlock (/Users/sebbie/repos/react/node_modules/jest-circus/build/run.js:126:9)
    +     at _runTestsForDescribeBlock (/Users/sebbie/repos/react/node_modules/jest-circus/build/run.js:121:9)
    +     at run (/Users/sebbie/repos/react/node_modules/jest-circus/build/run.js:71:3)
    +     at runAndTransformResultsToJestFormat (/Users/sebbie/repos/react/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    +     at jestAdapter (/Users/sebbie/repos/react/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    +     at runTestInternal (/Users/sebbie/repos/react/node_modules/jest-runner/build/runTest.js:367:16)
    +     at runTest (/Users/sebbie/repos/react/node_modules/jest-runner/build/runTest.js:444:34)
    +     at Object.worker (/Users/sebbie/repos/react/node_modules/jest-runner/build/testWorker.js:106:12)

How did you test this change?

  • added tests
  • used a branch build with Jest 29

@meta-cla meta-cla bot added the CLA Signed label Aug 5, 2025
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Aug 5, 2025
@react-sizebot
Copy link

react-sizebot commented Aug 5, 2025

Comparing: 7deda94...60b9844

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB +0.11% 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 530.04 kB 530.04 kB = 93.63 kB 93.63 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.11% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 654.48 kB 654.48 kB = 115.34 kB 115.34 kB
facebook-www/ReactDOM-prod.classic.js = 674.42 kB 674.42 kB = 118.68 kB 118.68 kB
facebook-www/ReactDOM-prod.modern.js = 664.84 kB 664.84 kB = 117.02 kB 117.03 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react/cjs/react.development.js +0.46% 45.54 kB 45.75 kB +0.78% 10.38 kB 10.46 kB
oss-stable/react/cjs/react.development.js +0.46% 45.56 kB 45.77 kB +0.80% 10.40 kB 10.49 kB
oss-experimental/react/cjs/react.development.js +0.43% 48.93 kB 49.14 kB +0.69% 11.09 kB 11.16 kB
facebook-react-native/react/cjs/React-dev.js +0.41% 51.48 kB 51.69 kB +0.58% 11.46 kB 11.53 kB
facebook-www/React-dev.modern.js +0.40% 52.44 kB 52.65 kB +0.77% 11.71 kB 11.80 kB
facebook-www/React-dev.classic.js +0.40% 52.44 kB 52.65 kB +0.77% 11.71 kB 11.80 kB
test_utils/ReactAllWarnings.js = 66.57 kB 66.04 kB = 16.72 kB 16.54 kB

Generated by 🚫 dangerJS against 60b9844

@eps1lon eps1lon force-pushed the sebbie/08-05-include_callsite_of_act_in_act_related_warnings branch 2 times, most recently from 0ac6061 to 94779fa Compare August 5, 2025 11:48
@eps1lon eps1lon force-pushed the sebbie/08-05-include_callsite_of_act_in_act_related_warnings branch from 94779fa to 60b9844 Compare August 5, 2025 11:57
@eps1lon eps1lon marked this pull request as ready for review August 5, 2025 13:25
@sebmarkbage
Copy link
Collaborator

Ideally, we shouldn't create Error objects with stack traces for regular errors. We never do that anywhere else because we shouldn't need to. In most scenarios it shouldn't be necessary at all because for example async stacks should work. I think unfortunately because the root of the stack is sync the regular zero-cost stacks don't work. The full async stacks attached by the debugger would work though.

Worst case scenario it should use console.createTask() to get the correct stack if something is delayed but ofc it's not implemented in many consoles. However, there another trick is we can set the current owner, in addition to console.createTask().

We can set the current owner on the isomorphic React that act is called on with a fake owner named "act()" whose JSX stack trace is the callsite of the act. Owners are basically our user space async stacks. That way createTask works if you have, or if not, if you've implemented owner stacks in the console like you should for other errors then that just works as a fallback.

This would solve this issue more generally for all errors inside the act and not just these three. I've had many issues with finding which line in a test was running when I get console.error inside a test for example because of the lack of the async stack.

@sebmarkbage
Copy link
Collaborator

I think if we used native async functions inside the act for our scheduling then this would also just work with the zero-cost stacks at least when it's awaited outside. The case when it wouldn't would be if you didn't await the act but if you did, by wouldn't that warn synchronously so you get the stack anyway?

@eps1lon
Copy link
Collaborator Author

eps1lon commented Aug 5, 2025

We never do that anywhere else because we shouldn't need to.

act is special because it's a testing utility and almost exclusively runs in a terminal based environment.

We're asking test frameworks to implement leverage captureOwnerStack which is a completely new lift.

stacks at least when it's awaited outside.

The main errors we're targetting here are the ones where the await is missing.

@eps1lon
Copy link
Collaborator Author

eps1lon commented Aug 5, 2025

I only filed this because I needed it for our tests. And I know I patched this in the past on other codebases. Others would probably find it useful as well when they start pulling in use into their codebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants