Commit Graph
12 Commits
Author SHA1 Message Date
Sebastian SilbermannandGitHub 3ac551e855 Dim console calls on additional Effect invocations due to StrictMode (#29007) 2024-05-22 11:39:54 +02:00
Sebastian SilbermannandGitHub 5cc9f69a74 Fix assertConsoleErrorDev on message mismatch with withoutStack: true (#29198)
## Summary

```js
assertConsoleErrorDev([
  ['Hello', {withoutStack: true}]
])
```

now errors with a helpful diff message if the message mismatched. See
first commit for previous behavior.

## How did you test this change?

- `yarn test --watch
packages/internal-test-utils/__tests__/ReactInternalTestUtils-test.js`
2024-05-21 12:48:41 -04:00
Sebastian SilbermannandGitHub 55dd0b1d0e Stop using Scheduler.log to test double invocations (#29008) 2024-05-21 00:30:45 +02:00
Sebastian SilbermannandGitHub 0c245df1dc Complete the typo fix (#28856) 2024-04-17 20:04:22 +02:00
f82051d7ab console test utils fix: match entire string, not just first letter (#28855)
Fixes issue where if the first letter of the expected string appeared
anywhere in actual message, the assertion would pass, leading to false
negatives. We should check the entire expected string.

---------

Co-authored-by: Ricky <rickhanlonii@gmail.com>
2024-04-17 13:04:54 -04:00
RickyandGitHub 608edcc90a [tests] add assertConsole<method>Dev helpers (#28732)
## Overview
**Internal React repo tests only**

Depends on https://github.com/facebook/react/pull/28710

Adds three new assertions:
- `assertConsoleLogDev`
- `assertConsoleWarnDev`
- `assertConsoleErrorDev`

These will replace this pattern:

```js
await expect(async () => {
  await expect(async () => {
    await act(() => {
      root.render(<Fail />)
    });
  }).toThrow();
}).toWarnDev('Warning');
```

With this:

```js
await expect(async () => {
  await act(() => {
    root.render(<Fail />)
  });
}).toThrow();

assertConsoleWarnDev('Warning');
```

It works similar to our other `assertLog` matchers which clear the log
and assert on it, failing the tests if the log is not asserted before
the test ends.

## Diffs

There are a few improvements I also added including better log diffs and
more logging.

When there's a failure, the output will look something like:

<img width="655" alt="Screenshot 2024-04-03 at 11 50 08 AM"
src="https://github.com/facebook/react/assets/2440089/0c4bf1b2-5f63-4204-8af3-09e0c2d752ad">


Check out the test suite for snapshots of all the failures we may log.
2024-04-11 08:19:46 -04:00
RickyandGitHub a5aedd1e15 Move console mocks to internal-test-utils (#28710)
Moving this to `internal-test-utils` so I can add helpers in the next PR
for:
- assertLogDev
- assertWarnDev
- assertErrorDev

Which will be exported from `internal-test-utils`. This isn't strictly
necessary, but it makes the factoring nicer, so internal-test-until
doesn't need to depend on `scripts/jest`.
2024-04-03 16:02:04 -04:00
RickyandGitHub cd63ef7921 Add simulateEventDispatch to test ReactDOMEventListener (#28079)
## Overview

For events, the browser will yield to microtasks between calling event
handers, allowing time to flush work inbetween. For example, in the
browser, this code will log the flushes between events:

```js
<body onclick="console.log('body'); Promise.resolve().then(() => console.log('flush body'));">
  <div onclick="console.log('div'); Promise.resolve().then(() => console.log('flush div'));">
    hi
  </div>
</body>

// Logs
div 
flush div 
body 
flush body 
```


[Sandbox](https://codesandbox.io/s/eloquent-noether-mw2cjg?file=/index.html)

The problem is, `dispatchEvent` (either in the browser, or JSDOM) does
not yield to microtasks. Which means, this code will log the flushes
after the events:

```js
const target = document.getElementsByTagName("div")[0];
const nativeEvent = document.createEvent("Event");

nativeEvent.initEvent("click", true, true);
target.dispatchEvent(nativeEvent);

// Logs
div
body
flush div
flush body
```

## The problem
This mostly isn't a problem because React attaches event handler at the
root, and calls the event handlers on components via the synthetic event
system. We handle flushing between calling event handlers as needed.

However, if you're mixing capture and bubbling events, or using multiple
roots, then the problem of not flushing microtasks between events can
come into play. This was found when converting a test to `createRoot` in
https://github.com/facebook/react/pull/28050#discussion_r1462118422, and
that test is an example of where this is an issue with nested roots.

Here's a sandox for
[discrete](https://codesandbox.io/p/sandbox/red-http-2wg8k5) and
[continuous](https://codesandbox.io/p/sandbox/gracious-voice-6r7tsc?file=%2Fsrc%2Findex.js%3A25%2C28)
events, showing how the test should behave. The existing test, when
switched to `createRoot` matches the browser behavior for continuous
events, but not discrete. Continuous events should be batched, and
discrete should flush individually.

## The fix

This PR implements the fix suggested by @sebmarkbage, to manually
traverse the path up from the element and dispatch events, yielding
between each call.
2024-02-08 16:06:03 -05:00
Andrew ClarkandGitHub 12a1d140e3 Don't prerender siblings of suspended component (#26380)
Today if something suspends, React will continue rendering the siblings
of that component.

Our original rationale for prerendering the siblings of a suspended
component was to initiate any lazy fetches that they might contain. This
was when we were more bullish about lazy fetching being a good idea some
of the time (when combined with prefetching), as opposed to our latest
thinking, which is that it's almost always a bad idea.

Another rationale for the original behavior was that the render was I/O
bound, anyway, so we might as do some extra work in the meantime. But
this was before we had the concept of instant loading states: when
navigating to a new screen, it's better to show a loading state as soon
as you can (often a skeleton UI), rather than delay the transition.
(There are still cases where we block the render, when a suitable
loading state is not available; it's just not _all_ cases where
something suspends.) So the biggest issue with our existing
implementation is that the prerendering of the siblings happens within
the same render pass as the one that suspended — _before_ the loading
state appears.

What we should do instead is immediately unwind the stack as soon as
something suspends, to unblock the loading state.

If we want to preserve the ability to prerender the siblings, what we
could do is schedule special render pass immediately after the fallback
is displayed. This is likely what we'll do in the future. However, in
the new implementation of `use`, there's another reason we don't
prerender siblings: so we can preserve the state of the stack when
something suspends, and resume where we left of when the promise
resolves without replaying the parents. The only way to do this
currently is to suspend the entire work loop. Fiber does not currently
support rendering multiple siblings in "parallel". Once you move onto
the next sibling, the stack of the previous sibling is discarded and
cannot be restored. We do plan to implement this feature, but it will
require a not-insignificant refactor.

Given that lazy data fetching is already bad for performance, the best
trade off for now seems to be to disable prerendering of siblings. This
gives us the best performance characteristics when you're following best
practices (i.e. hoist data fetches to Server Components or route
loaders), at the expense of making an already bad pattern a bit worse.

Later, when we implement resumable context stacks, we can reenable
sibling prerendering. Though even then the use case will mostly be to
prerender the CPU-bound work, not lazy fetches.
2023-03-21 10:24:56 -04:00
Andrew ClarkandGitHub 62cd5af08e Codemod redundant async act scopes (#26350)
Prior to #26347, our internal `act` API (not the public API) behaved
differently depending on whether the scope function returned a promise
(i.e. was an async function), for historical reasons that no longer
apply. Now that this is fixed, I've codemodded all async act scopes that
don't contain an await to be sync.

No pressing motivation other than it looks nicer and the codemod was
easy. Might help avoid confusion for new contributors who see async act
scopes with nothing async inside and infer it must be like that for a
reason.
2023-03-08 16:40:23 -05:00
Andrew ClarkandGitHub 44d3807945 Move internalAct to internal-test-utils package (#26344)
This is not a public API. We only use it for our internal tests, the
ones in this repo. Let's move it to this private package. Practically
speaking this will also let us use async/await in the implementation.
2023-03-08 12:58:31 -05:00
Andrew ClarkandGitHub 1528c5ccdf SchedulerMock.unstable_yieldValue -> SchedulerMock.log (#26312)
(This only affects our own internal repo; it's not a public API.)

I think most of us agree this is a less confusing name. It's possible
someone will confuse it with `console.log`. If that becomes a problem we
can warn in dev or something.
2023-03-06 11:09:07 -05:00