The changes to the test code relate to changes in JSDOM that come with Jest 25:
* Several JSDOM workarounds are no longer needed.
* Several tests made assertions to match incorrect JSDOM behavior (e.g. setAttribute calls) that JSDOM has now patched to match browsers.
* https://codesandbox.io/s/resets-value-of-datetime-input-to-fix-bugs-in-ios-safari-1ppwh
* JSDOM no longer triggers default actions when dispatching click events.
* https://codesandbox.io/s/beautiful-cdn-ugn8f
* JSDOM fixed (jsdom/jsdom#2700) a bug so that calling focus() on an already focused element does not dispatch a FocusEvent.
* JSDOM now supports passive events.
* JSDOM has improved support for custom CSS properties.
* But requires jsdom/cssstyle#112 to land to support webkit prefixed properties.
* Skip abandoned project folders in Jest config
This fixes a problem that occurs after renaming a package.
* Fix test_build_devtools to run test-build-devtools
* Exclude console.error plugin for DevTools packages
* Use correct release channel for DevTools tests
This should fix the createRoot error.
* Fix TZ dependent test
* Change DT job dependencies
* Replace all warning/lowPriWarning with console calls
* Replace console.warn/error with a custom wrapper at build time
* Fail the build for console.error/warn() where we can't read the stack
* prep for codemod
* prep warnings
* rename lint rules
* codemod for ifs
* shim www functions
* Handle more cases in the transform
* Thanks De Morgan
* Run the codemod
* Delete the transform
* Fix up confusing conditions manually
* Fix up www shims to match expected API
* Also check for low-pri warning in the lint rule
* Replace Babel plugin with an ESLint plugin
* Fix ESLint rule violations
* Move shared conditions higher
* Test formatting nits
* Tweak ESLint rule
* Bugfix: inside else branch, 'if' tests are not satisfactory
* Use a stricter check for exactly if (__DEV__)
This makes it easier to see what's going on and matches dominant style in the codebase.
* Fix remaining files after stricter check
* Add Flight Build and Unify HostFormat Config between Flight and Fizz
* Add basic resolution of models
* Add basic Flight fixture
Demonstrates the streaming protocol.
* Rename to flight-server to distinguish from the client parts
* Add Flight Client package and entry point
* Fix fixture
Special version of Jest's `it` for experimental tests. Tests marked as
experimental will run **both** stable and experimental modes. In
experimental mode, they work the same as the normal Jest methods. In
stable mode, they are **expected to fail**. This means we can detect
when a test previously marked as experimental can be un-marked when the
feature becomes stable. It also reduces the chances that we accidentally
add experimental APIs to the stable builds before we intend.
I added corresponding methods for the focus and skip APIs:
- `fit` -> `fit.experimental`
- `it.only` -> `it.only.experimental` or `it.experimental.only`
- `xit` -> `xit.experimental`
- `it.skip` -> `it.skip.experimental` or `it.experimental.skip`
Since `it` is an alias of `test`, `test.experimental` works, too.
* Tests run in experimental mode by default
For local development, you usually want experiments enabled. Unless
the release channel is set with an environment variable, tests will
run with __EXPERIMENTAL__ set to `true`.
* Remove concurrent APIs from stable builds
Those who want to try concurrent mode should use the experimental
builds instead.
I've left the `unstable_` prefixed APIs in the Facebook build so we
can continue experimenting with them internally without blessing them
for widespread use.
* Turn on SSR flags in experimental build
* Remove prefixed concurrent APIs from www build
Instead we'll use the experimental builds when syncing to www.
* Remove "canary" from internal React version string
* Don't bother including `unstable_` in error
The method names don't get stripped out of the production bundles
because they are passed as arguments to the error decoder.
Let's just always use the unprefixed APIs in the messages.
* Set up experimental builds
The experimental builds are packaged exactly like builds in the stable
release channel: same file structure, entry points, and npm package
names. The goal is to match what will eventually be released in stable
as closely as possible, but with additional features turned on.
Versioning and Releasing
------------------------
The experimental builds will be published to the same registry and
package names as the stable ones. However, they will be versioned using
a separate scheme. Instead of semver versions, experimental releases
will receive arbitrary version strings based on their content hashes.
The motivation is to thwart attempts to use a version range to match
against future experimental releases. The only way to install or depend
on an experimental release is to refer to the specific version number.
Building
--------
I did not use the existing feature flag infra to configure the
experimental builds. The reason is because feature flags are designed
to configure a single package. They're not designed to generate multiple
forks of the same package; for each set of feature flags, you must
create a separate package configuration.
Instead, I've added a new build dimension called the **release
channel**. By default, builds use the **stable** channel. There's
also an **experimental** release channel. We have the option to add more
in the future.
There are now two dimensions per artifact: build type (production,
development, or profiling), and release channel (stable or
experimental). These are separate dimensions because they are
combinatorial: there are stable and experimental production builds,
stable and experimental developmenet builds, and so on.
You can add something to an experimental build by gating on
`__EXPERIMENTAL__`, similar to how we use `__DEV__`. Anything inside
these branches will be excluded from the stable builds.
This gives us a low effort way to add experimental behavior in any
package without setting up feature flags or configuring a new package.
* Rename lowPriorityWarning to lowPriorityWarningWithoutStack
This maintains parity with the other warning-like functions.
* Duplicate the toWarnDev tests to test toLowPriorityWarnDev
* Make a lowPriorityWarning version of warning.js
* Extract both variants in print-warning
Avoids parsing lowPriorityWarning.js itself as the way it forwards the
call to lowPriorityWarningWithoutStack is not analyzable.
* Idle updates should not be blocked by hidden work
Use the special `Idle` expiration time for updates that are triggered at
Scheduler's `IdlePriority`, instead of `Never`.
The key difference between Idle and Never¹ is that Never work can be
committed in an inconsistent state without tearing the UI. The main
example is offscreen content, like a hidden subtree.
¹ "Never" isn't the best name. I originally called it that because it
"never" expires, but neither does Idle. Since it's mostly used for
offscreen subtrees, we could call it "Offscreen." However, it's also
used for dehydrated Suspense boundaries, which are inconsistent in the
sense that they haven't finished yet, but aren't visibly inconsistent
because the server rendered HTML matches what the hydrated tree would
look like.
* Reset as early as possible using local variable
* Updates in a hidden effect should be Idle
I had made them Never to avoid an extra render when a hidden effect
updates the hidden component -- if they are Idle, we have to render once
at Idle, which bails out on the hidden subtree, then again at Never to
actually process the update -- but the problem of needing an extra
render pass to bail out hidden updates already exists and we should fix
that properly instead of adding yet another special case.
If a Scheduler profile runs without stopping, the event log will grow
unbounded. Eventually it will run out of memory and the VM will throw
an error.
To prevent this from happening, let's automatically stop the profiler
once the log exceeds a certain limit. We'll also print a warning with
advice to call `stopLoggingProfilingEvents` explicitly.
Upgraded from Babel 6 to Babel 7.
The only significant change seems to be the way `@babel/plugin-transform-classes` handles classes differently from `babel-plugin-transform-es2015-classes`. In regular mode, the former injects a `_createClass` function that increases the bundle size, and in the latter it removes the safeguard checks. However, this is okay because we don't all classes in new features, and we want to deprecate class usage in the future in the react repo.
Co-authored-by: Luna Ruan <luna@fb.com>
Co-authored-by: Abdul Rauf <abdulraufmujahid@gmail.com>
Co-authored-by: Maksim Markelov <maks-markel@mail.ru>
We have behaviour divergence for act() between prod and dev (specifically, act() + concurrent mode does not flush fallbacks in prod. This doesn't affect anyone in OSS yet)
We also don't have a good story for writing tests in prod (and what from what I gather, nobody really writes tests in prod mode).
We could have wiped out act() in prod builds, except that _we_ ourselves use act() for our tests when we run them in prod mode.
This PR is a compromise to all of this. We will log a warning if you try to use act() in prod mode, and we silence it in our test suites.
The React Native build does not minify error messages in production,
but it still needs to run the error messages transform to compile
`invariant` calls to `ReactError`. To do this, I added a `noMinify`
option to the Babel plugin. I also renamed it from
`minify-error-messages` to the more generic `transform-error-messages`.
* Rewrite ReactFiberScheduler
Adds a new implementation of ReactFiberScheduler behind a feature flag.
We will maintain both implementations in parallel until the new one
is proven stable enough to replace the old one.
The main difference between the implementations is that the new one is
integrated with the Scheduler package's priority levels.
* Conditionally add fields to FiberRoot
Some fields only used by the old scheduler, and some by the new.
* Add separate build that enables new scheduler
* Re-enable skipped test
If synchronous updates are scheduled by a passive effect, that work
should be flushed synchronously, even if flushPassiveEffects is
called inside batchedUpdates.
* Passive effects have same priority as render
* Revert ability to cancel the current callback
React doesn't need this anyway because it never schedules callbacks if
it's already rendering.
* Revert change to FiberDebugPerf
Turns out this isn't neccessary.
* Fix ReactFiberScheduler dead code elimination
Should initialize to nothing, then assign the exports conditionally,
instead of initializing to the old exports and then reassigning to the
new ones.
* Don't yield before commit during sync error retry
* Call Scheduler.flushAll unconditionally in tests
Instead of wrapping in enableNewScheduler flag.
Adds a feature flag `enableNewScheduler` that toggles between two
implementations of ReactFiberScheduler. This will let us land changes in
master while preserving the ability to quickly rollback.
Ideally this will be a short-lived fork. Once we've tested the new
scheduler for a week or so without issues, we will get rid of it. Until
then, we'll need to maintain two parallel implementations and run tests
against both of them. We rarely land changes to ReactFiberScheduler, so
I don't expect this will be a huge burden.
This commit does not implement anything new. The flag is still off and
tests run against the existing implementation.
Use `yarn test-new-scheduler` to run tests against the new one.
* Transform invariant to custom error type
This transforms calls to the invariant module:
```js
invariant(condition, 'A %s message that contains %s', adj, noun);
```
Into throw statements:
```js
if (!condition) {
if (__DEV__) {
throw ReactError(`A ${adj} message that contains ${noun}`);
} else {
throw ReactErrorProd(ERR_CODE, adj, noun);
}
}
```
The only thing ReactError does is return an error whose name is set
to "Invariant Violation" to match the existing behavior.
ReactErrorProd is a special version used in production that throws
a minified error code, with a link to see to expanded form. This
replaces the reactProdInvariant module.
As a next step, I would like to replace our use of the invariant module
for user facing errors by transforming normal Error constructors to
ReactError and ReactErrorProd. (We can continue using invariant for
internal React errors that are meant to be unreachable, which was the
original purpose of invariant.)
* Use numbers instead of strings for error codes
* Use arguments instead of an array
I wasn't sure about this part so I asked Sebastian, and his rationale
was that using arguments will make ReactErrorProd slightly slower, but
using an array will likely make all the functions that throw slightly
slower to compile, so it's hard to say which way is better. But since
ReactErrorProd is in an error path, and fewer bytes is generally better,
no array is good.
* Casing nit
* Add command to run tests in persistent mode
* Convert Suspense fuzz tester to use noop renderer
So we can run it in persistent mode, too.
* Don't mutate stateNode in appendAllChildren
We can't mutate the stateNode in appendAllChildren because the children
could be current.
This is a bit weird because now the child that we append is different
from the one on the fiber stateNode. I think this makes conceptual
sense, but I suspect this likely breaks an assumption in Fabric.
With this approach, we no longer need to clone to unhide the children,
so I removed those host config methods.
Fixes bug surfaced by fuzz tester. (The test case that failed was the
one that's already hard coded.)
* In persistent mode, disable test that reads a ref
Refs behave differently in persistent mode. I added a TODO to write
a persistent mode version of this test.
* Run persistent mode tests in CI
* test-persistent should skip files without noop
If a file doesn't reference react-noop-renderer, we shouldn't bother
running it in persistent mode, since the results will be identical to
the normal test run.
* Remove module constructor from placeholder tests
We don't need this now that we have the ability to run any test file in
either mutation or persistent mode.
* Revert "test-persistent should skip files without noop"
Seb objected to adding shelljs as a dep and I'm too lazy to worry about
Windows support so whatever I'll just revert this.
* Delete duplicate file
* Swap expect(ReactNoop) for expect(Scheduler)
In the previous commits, I upgraded our custom Jest matchers for the
noop and test renderers to use Scheduler under the hood.
Now that all these matchers are using Scheduler, we can drop
support for passing ReactNoop and test roots and always pass
Scheduler directly.
* Externalize Scheduler in noop and test bundles
I also noticed we don't need to regenerator runtime in noop anymore.
* Replace test renderer's fake Scheduler implementation with mock build
The test renderer has its own mock implementation of the Scheduler
interface, with the ability to partially render work in tests. Now that
this functionality has been lifted into a proper mock Scheduler build,
we can use that instead.
* Fix Profiler tests in prod
* Replace noop's fake Scheduler implementation with mock Scheduler build
The noop renderer has its own mock implementation of the Scheduler
interface, with the ability to partially render work in tests. Now that
this functionality has been lifted into a proper mock Scheduler build,
we can use that instead.
Most of the existing noop tests were unaffected, but I did have to make
some changes. The biggest one involved passive effects: previously, they
were scheduled on a separate queue from the queue that handles
rendering. After this change, both rendering and effects are scheduled
in the Scheduler queue. I think this is a better approach because tests
no longer have to worry about the difference; if you call `flushAll`,
all the work is flushed, both rendering and effects. But for those few
tests that do care to flush the rendering without the effects, that's
still possible using the `yieldValue` API.
Follow-up: Do the same for test renderer.
* Fix import to scheduler/unstable_mock
* Add new mock build of Scheduler with flush, yield API
Test environments need a way to take control of the Scheduler queue and
incrementally flush work. Our current tests accomplish this either using
dynamic injection, or by using Jest's fake timers feature. Both of these
options are fragile and rely too much on implementation details.
In this new approach, we have a separate build of Scheduler that is
specifically designed for test environments. We mock the default
implementation like we would any other module; in our case, via Jest.
This special build has methods like `flushAll` and `yieldValue` that
control when work is flushed. These methods are based on equivalent
methods we've been using to write incremental React tests. Eventually
we may want to migrate the React tests to interact with the mock
Scheduler directly, instead of going through the host config like we
currently do.
For now, I'm using our custom static injection infrastructure to create
the two builds of Scheduler — a default build for DOM (which falls back
to a naive timer based implementation), and the new mock build. I did it
this way because it allows me to share most of the implementation, which
isn't specific to a host environment — e.g. everything related to the
priority queue. It may be better to duplicate the shared code instead,
especially considering that future environments (like React Native) may
have entirely forked implementations. I'd prefer to wait until the
implementation stabilizes before worrying about that, but I'm open to
changing this now if we decide it's important enough.
* Mock Scheduler in bundle tests, too
* Remove special case by making regex more restrictive
* Throw in tests if work is done before emptying log
Test renderer already does this. Makes it harder to miss unexpected
behavior by forcing you to assert on every logged value.
* Convert ReactNoop tests to use jest matchers
The matchers warn if work is flushed while the log is empty. This is
the pattern we already follow for test renderer. I've used the same APIs
as test renderer, so it should be easy to switch between the two.
* [Fizz] Add Flow/Jest/Rollup build infra
Add a new package for react-stream which allows for custom server renderer
outputs. I picked the name because it's a reasonable name but also
because the npm name is currently owned by a friend of the project.
The react-dom build has its own inlined server renderer under the
name `react-dom/fizz`.
There is also a noop renderer to be used for testing. At some point
we might add a public one to test-renderer but for now I don't want to have
to think about public API design for the tests.
* Add FormatConfig too
We need to separate the format (DOM, React Native, etc) from the host
running the server (Node, Browser, etc).
* Basic wiring between Node, Noop and DOM configs
The Node DOM API is pipeToNodeStream which accepts a writable stream.
* Merge host and format config in dynamic react-stream entry point
Simpler API this way but also avoids having to fork the wrapper config.
Fixes noop builds.
* Add setImmediate/Buffer globals to lint config
Used by the server renderer
* Properly include fizz.node.js
Also use forwarding to it from fizz.js in builds so that tests covers
this.
* Make react-stream private since we're not ready to publish
or even name it yet
* Rename Renderer -> Streamer
* Prefix react-dom/fizz with react-dom/unstable-fizz
* Add Fizz Browser host config
This lets Fizz render to WHATWG streams. E.g. for rendering in a
Service Worker.
I added react-dom/unstable-fizz.browser as the entry point for this.
Since we now have two configurations of DOM. I had to add another
inlinedHostConfigs configuration called `dom-browser`. The reconciler
treats this configuration the same as `dom`. For stream it checks
against the ReactFizzHostConfigBrowser instead of the Node one.
* Add Fizz Browser Fixture
This is for testing server rendering - on the client.
* Lower version number to detach it from react-reconciler version