Remove concurrent apis from stable (#17088)
* 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
This commit is contained in:
parent
4cb399a433
commit
30c5daf943
|
@ -98,7 +98,10 @@ jobs:
|
|||
- checkout
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test --maxWorkers=2
|
||||
|
||||
test_source_experimental:
|
||||
docker: *docker
|
||||
|
@ -120,7 +123,10 @@ jobs:
|
|||
- checkout
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test-persistent --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test-persistent --maxWorkers=2
|
||||
|
||||
test_source_prod:
|
||||
docker: *docker
|
||||
|
@ -130,7 +136,10 @@ jobs:
|
|||
- checkout
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test-prod --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test-prod --maxWorkers=2
|
||||
|
||||
build:
|
||||
docker: *docker
|
||||
|
@ -217,7 +226,23 @@ jobs:
|
|||
- attach_workspace: *attach_workspace
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test-build --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test-build --maxWorkers=2
|
||||
|
||||
test_build_experimental:
|
||||
docker: *docker
|
||||
environment: *environment
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace: *attach_workspace
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: experimental
|
||||
command: yarn test-build --maxWorkers=2
|
||||
|
||||
test_build_devtools:
|
||||
docker: *docker
|
||||
|
@ -227,7 +252,10 @@ jobs:
|
|||
- attach_workspace: *attach_workspace
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test-build-devtools --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test-build --maxWorkers=2
|
||||
|
||||
test_dom_fixtures:
|
||||
docker: *docker
|
||||
|
@ -238,6 +266,8 @@ jobs:
|
|||
- *restore_yarn_cache
|
||||
- run:
|
||||
name: Run DOM fixture tests
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: |
|
||||
cd fixtures/dom
|
||||
yarn --frozen-lockfile
|
||||
|
@ -265,7 +295,23 @@ jobs:
|
|||
- attach_workspace: *attach_workspace
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run: yarn test-build-prod --maxWorkers=2
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: stable
|
||||
command: yarn test-build-prod --maxWorkers=2
|
||||
|
||||
test_build_prod_experimental:
|
||||
docker: *docker
|
||||
environment: *environment
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace: *attach_workspace
|
||||
- *restore_yarn_cache
|
||||
- *run_yarn
|
||||
- run:
|
||||
environment:
|
||||
RELEASE_CHANNEL: experimental
|
||||
command: yarn test-build-prod --maxWorkers=2
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
@ -324,6 +370,12 @@ workflows:
|
|||
- process_artifacts_experimental:
|
||||
requires:
|
||||
- build_experimental
|
||||
- test_build_experimental:
|
||||
requires:
|
||||
- build_experimental
|
||||
- test_build_prod_experimental:
|
||||
requires:
|
||||
- build_experimental
|
||||
|
||||
fuzz_tests:
|
||||
triggers:
|
||||
|
|
|
@ -17,6 +17,7 @@ let TestRenderer;
|
|||
let ARTTest;
|
||||
|
||||
global.__DEV__ = process.env.NODE_ENV !== 'production';
|
||||
global.__EXPERIMENTAL__ = process.env.RELEASE_CHANNEL === 'experimental';
|
||||
|
||||
expect.extend(require('../toWarnDev'));
|
||||
|
||||
|
@ -176,8 +177,9 @@ it("doesn't warn if you use nested acts from different renderers", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('warns when using createRoot() + .render', () => {
|
||||
const root = ReactDOM.unstable_createRoot(document.createElement('div'));
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('warns when using createRoot() + .render', () => {
|
||||
const root = ReactDOM.createRoot(document.createElement('div'));
|
||||
expect(() => {
|
||||
TestRenderer.act(() => {
|
||||
root.render(<App />);
|
||||
|
@ -191,4 +193,5 @@ it('warns when using createRoot() + .render', () => {
|
|||
withoutStack: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,493 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 1`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 2`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 3`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 4`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<B key="b">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 5`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 6`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 7`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 8`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 9`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 10`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
<Suspense>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 11`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<B key="b">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense (Concurrent Mode) 12`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 1`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 2`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 3`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 4`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key="c">
|
||||
<B key="b">
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 5`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 6`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 7`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 8`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 9`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 10`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 11`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<B key="b">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 12`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key="a">
|
||||
<Z>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 13`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 14`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 15`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 16`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<B key="b">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 17`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 18`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 19`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 20`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 21`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 22`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
<Suspense>
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 23`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<B key="b">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test for Suspense without type change (Concurrent Mode) 24`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key="a">
|
||||
<Y>
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test with different tree operations (Concurrent Mode): 1: abcde 1`] = `
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle a stress test with different tree operations (Concurrent Mode): 2: abxde 1`] = `
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
▾ <C key="c">
|
||||
<X>
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 1`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<A key="a">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 2`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<B key="b">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 3`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<C key="c">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 4`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<D key="d">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 5`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<E key="e">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 6`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<A key="a">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 7`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<B key="b">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 8`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<C key="c">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 9`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<D key="d">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 10`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<E key="e">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 11`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 12`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<B key="b">
|
||||
<A key="a">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 13`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 14`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<C key="c">
|
||||
<B key="b">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 15`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<A key="a">
|
||||
<C key="c">
|
||||
`;
|
||||
|
||||
exports[`StoreStressConcurrent should handle stress test with reordering (Concurrent Mode) 16`] = `
|
||||
[root]
|
||||
▾ <Root>
|
||||
<C key="c">
|
||||
<A key="a">
|
||||
`;
|
|
@ -27,6 +27,11 @@ describe('StoreStressConcurrent', () => {
|
|||
print = require('./storeSerializer').print;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a stress test for the tree mount/update/unmount traversal.
|
||||
// It renders different trees that should produce the same output.
|
||||
it('should handle a stress test with different tree operations (Concurrent Mode)', () => {
|
||||
|
@ -57,9 +62,19 @@ describe('StoreStressConcurrent', () => {
|
|||
// 1. Render a normal version of [a, b, c, d, e].
|
||||
let container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
let root = ReactDOM.unstable_createRoot(container);
|
||||
let root = ReactDOM.createRoot(container);
|
||||
act(() => root.render(<Parent>{[a, b, c, d, e]}</Parent>));
|
||||
expect(store).toMatchSnapshot('1: abcde');
|
||||
expect(store).toMatchInlineSnapshot(
|
||||
`
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
<C key="c">
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`,
|
||||
);
|
||||
expect(container.textContent).toMatch('abcde');
|
||||
const snapshotForABCDE = print(store);
|
||||
|
||||
|
@ -68,7 +83,18 @@ describe('StoreStressConcurrent', () => {
|
|||
act(() => {
|
||||
setShowX(true);
|
||||
});
|
||||
expect(store).toMatchSnapshot('2: abxde');
|
||||
expect(store).toMatchInlineSnapshot(
|
||||
`
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
<B key="b">
|
||||
▾ <C key="c">
|
||||
<X>
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`,
|
||||
);
|
||||
expect(container.textContent).toMatch('abxde');
|
||||
const snapshotForABXDE = print(store);
|
||||
|
||||
|
@ -120,7 +146,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Ensure fresh mount.
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
|
||||
// Verify mounting 'abcde'.
|
||||
act(() => root.render(<Parent>{cases[i]}</Parent>));
|
||||
|
@ -150,7 +176,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// There'll be no unmounting until the very end.
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
for (let i = 0; i < cases.length; i++) {
|
||||
// Verify mounting 'abcde'.
|
||||
act(() => root.render(<Parent>{cases[i]}</Parent>));
|
||||
|
@ -216,22 +242,80 @@ describe('StoreStressConcurrent', () => {
|
|||
let snapshots = [];
|
||||
let container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
let root = ReactDOM.unstable_createRoot(container);
|
||||
let root = ReactDOM.createRoot(container);
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
act(() => root.render(<Root>{steps[i]}</Root>));
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
expect(store).toMatchSnapshot();
|
||||
snapshots.push(print(store));
|
||||
act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
||||
expect(snapshots).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<A key=\\"a\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<B key=\\"b\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<C key=\\"c\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<D key=\\"d\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<E key=\\"e\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<A key=\\"a\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<B key=\\"b\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<C key=\\"c\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<D key=\\"d\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<E key=\\"e\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<A key=\\"a\\">
|
||||
<B key=\\"b\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<B key=\\"b\\">
|
||||
<A key=\\"a\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<B key=\\"b\\">
|
||||
<C key=\\"c\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<C key=\\"c\\">
|
||||
<B key=\\"b\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<A key=\\"a\\">
|
||||
<C key=\\"c\\">",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">",
|
||||
]
|
||||
`);
|
||||
|
||||
// 2. Verify that we can update from every step to every other step and back.
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
for (let j = 0; j < steps.length; j++) {
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() => root.render(<Root>{steps[i]}</Root>));
|
||||
expect(print(store)).toMatch(snapshots[i]);
|
||||
act(() => root.render(<Root>{steps[j]}</Root>));
|
||||
|
@ -248,7 +332,7 @@ describe('StoreStressConcurrent', () => {
|
|||
for (let j = 0; j < steps.length; j++) {
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -320,7 +404,7 @@ describe('StoreStressConcurrent', () => {
|
|||
let snapshots = [];
|
||||
let container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
let root = ReactDOM.unstable_createRoot(container);
|
||||
let root = ReactDOM.createRoot(container);
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
act(() =>
|
||||
root.render(
|
||||
|
@ -331,13 +415,96 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
expect(store).toMatchSnapshot();
|
||||
// We snapshot each step once so it doesn't regress.d
|
||||
snapshots.push(print(store));
|
||||
act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
||||
expect(snapshots).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<B key=\\"b\\">
|
||||
<C key=\\"c\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key=\\"c\\">
|
||||
<B key=\\"b\\">
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<B key=\\"b\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
<Suspense>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<B key=\\"b\\">
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
<A key=\\"a\\">
|
||||
<Y>",
|
||||
]
|
||||
`);
|
||||
|
||||
// 2. Verify check Suspense can render same steps as initial fallback content.
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
act(() =>
|
||||
|
@ -364,7 +531,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -410,7 +577,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -468,7 +635,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -518,7 +685,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -572,7 +739,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -726,7 +893,7 @@ describe('StoreStressConcurrent', () => {
|
|||
let snapshots = [];
|
||||
let container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
let root = ReactDOM.unstable_createRoot(container);
|
||||
let root = ReactDOM.createRoot(container);
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
act(() =>
|
||||
root.render(
|
||||
|
@ -740,7 +907,6 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
expect(store).toMatchSnapshot();
|
||||
snapshots.push(print(store));
|
||||
act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
@ -765,19 +931,126 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
expect(store).toMatchSnapshot();
|
||||
fallbackSnapshots.push(print(store));
|
||||
act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
||||
expect(snapshots).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<B key=\\"b\\">
|
||||
<C key=\\"c\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key=\\"c\\">
|
||||
<B key=\\"b\\">
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<C key=\\"c\\">
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<B key=\\"b\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<B key=\\"b\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
"[root]
|
||||
▾ <Root>
|
||||
<X>
|
||||
▾ <Suspense>
|
||||
▾ <MaybeSuspend>
|
||||
<A key=\\"a\\">
|
||||
<Z>
|
||||
<Y>",
|
||||
]
|
||||
`);
|
||||
|
||||
// 3. Verify we can update from each step to each step in primary mode.
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
for (let j = 0; j < steps.length; j++) {
|
||||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -829,7 +1102,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -896,7 +1169,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -948,7 +1221,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
@ -1000,7 +1273,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// Always start with a fresh container and steps[i].
|
||||
container = document.createElement('div');
|
||||
// $FlowFixMe
|
||||
root = ReactDOM.unstable_createRoot(container);
|
||||
root = ReactDOM.createRoot(container);
|
||||
act(() =>
|
||||
root.render(
|
||||
<Root>
|
||||
|
|
|
@ -47,6 +47,16 @@ describe('ReactDOMFiberAsync', () => {
|
|||
expect(ops).toEqual(['Hi', 'Bye']);
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
describe('concurrent mode', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
ReactDOM = require('react-dom');
|
||||
Scheduler = require('scheduler');
|
||||
});
|
||||
|
||||
it('does not perform deferred updates synchronously', () => {
|
||||
let inputRef = React.createRef();
|
||||
let asyncValueRef = React.createRef();
|
||||
|
@ -83,14 +93,16 @@ describe('ReactDOMFiberAsync', () => {
|
|||
);
|
||||
}
|
||||
}
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Counter />);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(asyncValueRef.current.textContent).toBe('');
|
||||
expect(syncValueRef.current.textContent).toBe('');
|
||||
|
||||
setUntrackedInputValue.call(inputRef.current, 'hello');
|
||||
inputRef.current.dispatchEvent(new MouseEvent('input', {bubbles: true}));
|
||||
inputRef.current.dispatchEvent(
|
||||
new MouseEvent('input', {bubbles: true}),
|
||||
);
|
||||
// Should only flush non-deferred update.
|
||||
expect(asyncValueRef.current.textContent).toBe('');
|
||||
expect(syncValueRef.current.textContent).toBe('hello');
|
||||
|
@ -102,17 +114,8 @@ describe('ReactDOMFiberAsync', () => {
|
|||
expect(syncValueRef.current.textContent).toBe('hello');
|
||||
});
|
||||
|
||||
describe('concurrent mode', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
ReactDOM = require('react-dom');
|
||||
Scheduler = require('scheduler');
|
||||
});
|
||||
|
||||
it('top-level updates are concurrent', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
expect(container.textContent).toEqual('');
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -134,7 +137,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
}
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Component />);
|
||||
expect(container.textContent).toEqual('');
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -262,7 +265,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
}
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Component />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
||||
|
@ -303,7 +306,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
return this.state.counter;
|
||||
}
|
||||
}
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Counter />);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('0');
|
||||
|
@ -414,7 +417,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
}
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Form />);
|
||||
// Flush
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -470,7 +473,9 @@ describe('ReactDOMFiberAsync', () => {
|
|||
</button>
|
||||
<button
|
||||
onClick={
|
||||
this.state.active ? this.submitForm : this.disabledSubmitForm
|
||||
this.state.active
|
||||
? this.submitForm
|
||||
: this.disabledSubmitForm
|
||||
}
|
||||
ref={submitButtonRef}>
|
||||
Submit
|
||||
|
@ -480,7 +485,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
}
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Form />);
|
||||
// Flush
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -540,7 +545,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
}
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Form />);
|
||||
// Flush
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -572,7 +577,7 @@ describe('ReactDOMFiberAsync', () => {
|
|||
|
||||
describe('createSyncRoot', () => {
|
||||
it('updates flush without yielding in the next event', () => {
|
||||
const root = ReactDOM.unstable_createSyncRoot(container);
|
||||
const root = ReactDOM.createSyncRoot(container);
|
||||
|
||||
function Text(props) {
|
||||
Scheduler.unstable_yieldValue(props.text);
|
||||
|
@ -594,10 +599,6 @@ describe('ReactDOMFiberAsync', () => {
|
|||
expect(Scheduler).toFlushExpired(['A', 'B', 'C']);
|
||||
expect(container.textContent).toEqual('ABC');
|
||||
});
|
||||
|
||||
it('does not support createBatch', () => {
|
||||
const root = ReactDOM.unstable_createSyncRoot(container);
|
||||
expect(root.createBatch).toBe(undefined);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -105,6 +105,7 @@ describe('ReactDOMHooks', () => {
|
|||
expect(labelRef.current.innerHTML).toBe('abc');
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('should not bail out when an update is scheduled from within an event handler in Concurrent Mode', () => {
|
||||
const {createRef, useCallback, useState} = React;
|
||||
|
||||
|
@ -125,7 +126,7 @@ describe('ReactDOMHooks', () => {
|
|||
const inputRef = createRef();
|
||||
const labelRef = createRef();
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Example inputRef={inputRef} labelRef={labelRef} />);
|
||||
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -139,4 +140,5 @@ describe('ReactDOMHooks', () => {
|
|||
|
||||
expect(labelRef.current.innerHTML).toBe('abc');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -26,15 +26,22 @@ describe('ReactDOMRoot', () => {
|
|||
Scheduler = require('scheduler');
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it('createRoot is not exposed in stable build', () => {
|
||||
expect(ReactDOM.createRoot).toBe(undefined);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
it('renders children', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
});
|
||||
|
||||
it('unmounts children', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
|
@ -57,7 +64,7 @@ describe('ReactDOMRoot', () => {
|
|||
// Does not hydrate by default
|
||||
const container1 = document.createElement('div');
|
||||
container1.innerHTML = markup;
|
||||
const root1 = ReactDOM.unstable_createRoot(container1);
|
||||
const root1 = ReactDOM.createRoot(container1);
|
||||
root1.render(
|
||||
<div>
|
||||
<span />
|
||||
|
@ -68,7 +75,7 @@ describe('ReactDOMRoot', () => {
|
|||
// Accepts `hydrate` option
|
||||
const container2 = document.createElement('div');
|
||||
container2.innerHTML = markup;
|
||||
const root2 = ReactDOM.unstable_createRoot(container2, {hydrate: true});
|
||||
const root2 = ReactDOM.createRoot(container2, {hydrate: true});
|
||||
root2.render(
|
||||
<div>
|
||||
<span />
|
||||
|
@ -81,7 +88,7 @@ describe('ReactDOMRoot', () => {
|
|||
|
||||
it('does not clear existing children', async () => {
|
||||
container.innerHTML = '<div>a</div><div>b</div>';
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(
|
||||
<div>
|
||||
<span>c</span>
|
||||
|
@ -102,12 +109,12 @@ describe('ReactDOMRoot', () => {
|
|||
|
||||
it('throws a good message on invalid containers', () => {
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createRoot(<div>Hi</div>);
|
||||
ReactDOM.createRoot(<div>Hi</div>);
|
||||
}).toThrow('createRoot(...): Target container is not a DOM element.');
|
||||
});
|
||||
|
||||
it('warns when rendering with legacy API into createRoot() container', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
|
@ -130,7 +137,7 @@ describe('ReactDOMRoot', () => {
|
|||
});
|
||||
|
||||
it('warns when hydrating with legacy API into createRoot() container', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
|
@ -150,7 +157,7 @@ describe('ReactDOMRoot', () => {
|
|||
});
|
||||
|
||||
it('warns when unmounting with legacy API (no previous content)', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
|
@ -179,7 +186,7 @@ describe('ReactDOMRoot', () => {
|
|||
// Currently createRoot().render() doesn't clear this.
|
||||
container.appendChild(document.createElement('div'));
|
||||
// The rest is the same as test above.
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<div>Hi</div>);
|
||||
Scheduler.unstable_flushAll();
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
|
@ -198,7 +205,7 @@ describe('ReactDOMRoot', () => {
|
|||
it('warns when passing legacy container to createRoot()', () => {
|
||||
ReactDOM.render(<div>Hi</div>, container);
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createRoot(container);
|
||||
ReactDOM.createRoot(container);
|
||||
}).toWarnDev(
|
||||
'You are calling ReactDOM.createRoot() on a container that was previously ' +
|
||||
'passed to ReactDOM.render(). This is not supported.',
|
||||
|
|
|
@ -75,7 +75,6 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
jest.resetModuleRegistry();
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSuspenseServerRenderer = true;
|
||||
ReactFeatureFlags.enableSuspenseCallback = true;
|
||||
ReactFeatureFlags.enableFlareAPI = true;
|
||||
|
||||
|
@ -90,6 +89,11 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
useHover = require('react-interactions/events/hover').useHover;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
it('hydrates a parent even if a child Suspense boundary is blocked', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -130,7 +134,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -200,7 +204,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// hydrating anyway.
|
||||
suspend = true;
|
||||
suspend2 = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {
|
||||
let root = ReactDOM.createRoot(container, {
|
||||
hydrate: true,
|
||||
hydrationOptions: {
|
||||
onHydrated(node) {
|
||||
|
@ -273,7 +277,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {
|
||||
let root = ReactDOM.createRoot(container, {
|
||||
hydrate: true,
|
||||
hydrationOptions: {
|
||||
onDeleted(node) {
|
||||
|
@ -411,7 +415,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
suspend = true;
|
||||
|
||||
act(() => {
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
});
|
||||
|
||||
|
@ -468,7 +472,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// hydrating anyway.
|
||||
suspend = true;
|
||||
act(() => {
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
});
|
||||
|
||||
|
@ -518,7 +522,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App text="Hello" className="hello" />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -587,7 +591,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App text="Hello" className="hello" />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -660,7 +664,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App text="Hello" className="hello" />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -732,7 +736,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App text="Hello" className="hello" />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -803,7 +807,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App text="Hello" className="hello" />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -889,7 +893,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(
|
||||
<Context.Provider value={{text: 'Hello', className: 'hello'}}>
|
||||
<App />
|
||||
|
@ -971,7 +975,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(
|
||||
<Context.Provider value={{text: 'Hello', className: 'hello'}}>
|
||||
<App />
|
||||
|
@ -1049,7 +1053,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// On the client we have the data available quickly for some reason.
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1105,7 +1109,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// On the client we have the data available quickly for some reason.
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
// This will have exceeded the suspended time so we should timeout.
|
||||
|
@ -1166,7 +1170,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// On the client we have the data available quickly for some reason.
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
// This will have exceeded the suspended time so we should timeout.
|
||||
|
@ -1242,7 +1246,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// Attempt to hydrate the content.
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1335,7 +1339,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// Attempt to hydrate the content.
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1413,7 +1417,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
let spanB = container.getElementsByTagName('span')[1];
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
suspend = true;
|
||||
act(() => {
|
||||
|
@ -1495,7 +1499,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
let spanA = container.getElementsByTagName('span')[0];
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
suspend = true;
|
||||
act(() => {
|
||||
|
@ -1575,7 +1579,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// Put the suspense node in pending state.
|
||||
suspenseNode.data = '$?';
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
suspend = true;
|
||||
act(() => {
|
||||
|
@ -1652,7 +1656,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
let span = container.getElementsByTagName('span')[1];
|
||||
|
||||
suspend = false;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1695,7 +1699,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1748,7 +1752,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(
|
||||
<ClassName.Provider value={'hello'}>
|
||||
<App text="Hello" />
|
||||
|
@ -1840,7 +1844,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -1914,7 +1918,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// We'll do one click before hydrating.
|
||||
|
@ -1995,7 +1999,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// We'll do one click before hydrating.
|
||||
|
@ -2072,7 +2076,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// We'll do one click before hydrating.
|
||||
|
@ -2151,7 +2155,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// On the client we don't have all data yet but we want to start
|
||||
// hydrating anyway.
|
||||
suspend = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
|
@ -2216,7 +2220,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
// We're going to use a different root as a parent.
|
||||
// This lets us detect whether an event goes through React's event system.
|
||||
let parentRoot = ReactDOM.unstable_createRoot(parentContainer);
|
||||
let parentRoot = ReactDOM.createRoot(parentContainer);
|
||||
parentRoot.render(<Parent />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
||||
|
@ -2229,7 +2233,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
suspend = true;
|
||||
|
||||
// Hydrate asynchronously.
|
||||
let root = ReactDOM.unstable_createRoot(childContainer, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(childContainer, {hydrate: true});
|
||||
root.render(<App />);
|
||||
jest.runAllTimers();
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -2319,7 +2323,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// hydrating anyway.
|
||||
suspend1 = true;
|
||||
suspend2 = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -2434,7 +2438,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
// hydrating anyway.
|
||||
suspend1 = true;
|
||||
suspend2 = true;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
Scheduler.unstable_flushAll();
|
||||
|
|
|
@ -13,7 +13,6 @@ let React;
|
|||
let ReactDOM;
|
||||
let ReactDOMServer;
|
||||
let Scheduler;
|
||||
let ReactFeatureFlags;
|
||||
let Suspense;
|
||||
|
||||
function dispatchMouseHoverEvent(to, from) {
|
||||
|
@ -93,10 +92,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSuspenseServerRenderer = true;
|
||||
ReactFeatureFlags.enableSelectiveHydration = true;
|
||||
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMServer = require('react-dom/server');
|
||||
|
@ -104,6 +99,11 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
Suspense = React.Suspense;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
it('hydrates the target boundary synchronously during a click', async () => {
|
||||
function Child({text}) {
|
||||
Scheduler.unstable_yieldValue(text);
|
||||
|
@ -144,7 +144,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
|
||||
let span = container.getElementsByTagName('span')[1];
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// Nothing has been hydrated so far.
|
||||
|
@ -223,7 +223,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
|
||||
// A and D will be suspended. We'll click on D which should take
|
||||
// priority, after we unsuspend.
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// Nothing has been hydrated so far.
|
||||
|
@ -309,7 +309,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
|
||||
// A and D will be suspended. We'll click on D which should take
|
||||
// priority, after we unsuspend.
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// Nothing has been hydrated so far.
|
||||
|
@ -405,7 +405,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
|
||||
// A and D will be suspended. We'll click on D which should take
|
||||
// priority, after we unsuspend.
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// Nothing has been hydrated so far.
|
||||
|
@ -474,7 +474,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
let spanB = container.getElementsByTagName('span')[1];
|
||||
let spanC = container.getElementsByTagName('span')[2];
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// Nothing has been hydrated so far.
|
||||
|
|
|
@ -14,16 +14,12 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
|
|||
let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMServer;
|
||||
let ReactFeatureFlags;
|
||||
let ReactTestUtils;
|
||||
|
||||
function initModules() {
|
||||
// Reset warning cache.
|
||||
jest.resetModuleRegistry();
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSuspenseServerRenderer = true;
|
||||
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMServer = require('react-dom/server');
|
||||
|
@ -48,6 +44,11 @@ describe('ReactDOMServerSuspense', () => {
|
|||
resetModules();
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
function Text(props) {
|
||||
return <div>{props.text}</div>;
|
||||
}
|
||||
|
@ -125,7 +126,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
expect(divB.textContent).toBe('B');
|
||||
|
||||
ReactTestUtils.act(() => {
|
||||
const root = ReactDOM.unstable_createSyncRoot(parent, {hydrate: true});
|
||||
const root = ReactDOM.createSyncRoot(parent, {hydrate: true});
|
||||
root.render(example);
|
||||
});
|
||||
|
||||
|
|
|
@ -682,6 +682,7 @@ describe('ReactDOMServer', () => {
|
|||
expect(markup).toBe('<div></div>');
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it('throws for unsupported types on the server', () => {
|
||||
expect(() => {
|
||||
ReactDOMServer.renderToString(<React.Suspense />);
|
||||
|
@ -714,6 +715,7 @@ describe('ReactDOMServer', () => {
|
|||
ReactDOMServer.renderToString(<AsyncFoo />);
|
||||
}).toThrow('ReactDOMServer does not yet support Suspense.');
|
||||
});
|
||||
}
|
||||
|
||||
it('does not get confused by throwing null', () => {
|
||||
function Bad() {
|
||||
|
|
|
@ -500,11 +500,12 @@ describe('ReactDOMServerHydration', () => {
|
|||
expect(element.textContent).toBe('Hello world');
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('does not re-enter hydration after committing the first one', () => {
|
||||
let finalHTML = ReactDOMServer.renderToString(<div />);
|
||||
let container = document.createElement('div');
|
||||
container.innerHTML = finalHTML;
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
let root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
root.render(<div />);
|
||||
Scheduler.unstable_flushAll();
|
||||
root.render(null);
|
||||
|
@ -514,152 +515,8 @@ describe('ReactDOMServerHydration', () => {
|
|||
root.render(<div />);
|
||||
Scheduler.unstable_flushAll();
|
||||
});
|
||||
|
||||
it('does not invoke an event on a concurrent hydrating node until it commits', () => {
|
||||
function Sibling({text}) {
|
||||
Scheduler.unstable_yieldValue('Sibling');
|
||||
return <span>Sibling</span>;
|
||||
}
|
||||
|
||||
function Sibling2({text}) {
|
||||
Scheduler.unstable_yieldValue('Sibling2');
|
||||
return null;
|
||||
}
|
||||
|
||||
let clicks = 0;
|
||||
|
||||
function Button() {
|
||||
Scheduler.unstable_yieldValue('Button');
|
||||
let [clicked, setClicked] = React.useState(false);
|
||||
if (clicked) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<a
|
||||
onClick={() => {
|
||||
setClicked(true);
|
||||
clicks++;
|
||||
}}>
|
||||
Click me
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Button />
|
||||
<Sibling />
|
||||
<Sibling2 />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let finalHTML = ReactDOMServer.renderToString(<App />);
|
||||
let container = document.createElement('div');
|
||||
container.innerHTML = finalHTML;
|
||||
expect(Scheduler).toHaveYielded(['Button', 'Sibling', 'Sibling2']);
|
||||
|
||||
// We need this to be in the document since we'll dispatch events on it.
|
||||
document.body.appendChild(container);
|
||||
|
||||
let a = container.getElementsByTagName('a')[0];
|
||||
|
||||
// Hydrate asynchronously.
|
||||
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
root.render(<App />);
|
||||
|
||||
// We haven't started hydrating yet.
|
||||
a.click();
|
||||
// Clicking should not invoke the event yet because we haven't committed
|
||||
// the hydration yet.
|
||||
expect(clicks).toBe(0);
|
||||
|
||||
// Flush part way through the render.
|
||||
if (__DEV__) {
|
||||
// In DEV effects gets double invoked.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Button', 'Button', 'Sibling']);
|
||||
} else {
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Button', 'Sibling']);
|
||||
}
|
||||
|
||||
expect(container.textContent).toBe('Click meSibling');
|
||||
|
||||
// We're now partially hydrated.
|
||||
a.click();
|
||||
// Clicking should not invoke the event yet because we haven't committed
|
||||
// the hydration yet.
|
||||
expect(clicks).toBe(0);
|
||||
|
||||
// Finish the rest of the hydration.
|
||||
if (__DEV__) {
|
||||
// In DEV effects gets double invoked.
|
||||
expect(Scheduler).toFlushAndYield(['Sibling2', 'Button', 'Button']);
|
||||
} else {
|
||||
expect(Scheduler).toFlushAndYield(['Sibling2', 'Button']);
|
||||
}
|
||||
|
||||
// We should have picked up both events now.
|
||||
expect(clicks).toBe(2);
|
||||
|
||||
expect(container.textContent).toBe('Sibling');
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
it('does not invoke an event on a parent tree when a subtree is hydrating', () => {
|
||||
let clicks = 0;
|
||||
let childSlotRef = React.createRef();
|
||||
|
||||
function Parent() {
|
||||
return <div onClick={() => clicks++} ref={childSlotRef} />;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<a>Click me</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let finalHTML = ReactDOMServer.renderToString(<App />);
|
||||
|
||||
let parentContainer = document.createElement('div');
|
||||
let childContainer = document.createElement('div');
|
||||
|
||||
// We need this to be in the document since we'll dispatch events on it.
|
||||
document.body.appendChild(parentContainer);
|
||||
|
||||
// We're going to use a different root as a parent.
|
||||
// This lets us detect whether an event goes through React's event system.
|
||||
let parentRoot = ReactDOM.unstable_createRoot(parentContainer);
|
||||
parentRoot.render(<Parent />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
||||
childSlotRef.current.appendChild(childContainer);
|
||||
|
||||
childContainer.innerHTML = finalHTML;
|
||||
|
||||
let a = childContainer.getElementsByTagName('a')[0];
|
||||
|
||||
// Hydrate asynchronously.
|
||||
let root = ReactDOM.unstable_createRoot(childContainer, {hydrate: true});
|
||||
root.render(<App />);
|
||||
// Nothing has rendered so far.
|
||||
|
||||
a.click();
|
||||
expect(clicks).toBe(0);
|
||||
|
||||
Scheduler.unstable_flushAll();
|
||||
|
||||
// We're now full hydrated.
|
||||
|
||||
expect(clicks).toBe(1);
|
||||
|
||||
document.body.removeChild(parentContainer);
|
||||
});
|
||||
|
||||
it('regression test: Suspense + hydration in legacy mode ', () => {
|
||||
const element = document.createElement('div');
|
||||
element.innerHTML = '<div>Hello World</div>';
|
||||
|
|
|
@ -27,22 +27,23 @@ function sleep(period) {
|
|||
|
||||
describe('ReactTestUtils.act()', () => {
|
||||
// first we run all the tests with concurrent mode
|
||||
if (__EXPERIMENTAL__) {
|
||||
let concurrentRoot = null;
|
||||
function renderConcurrent(el, dom) {
|
||||
concurrentRoot = ReactDOM.unstable_createRoot(dom);
|
||||
const renderConcurrent = (el, dom) => {
|
||||
concurrentRoot = ReactDOM.createRoot(dom);
|
||||
concurrentRoot.render(el);
|
||||
}
|
||||
};
|
||||
|
||||
function unmountConcurrent(_dom) {
|
||||
const unmountConcurrent = _dom => {
|
||||
if (concurrentRoot !== null) {
|
||||
concurrentRoot.unmount();
|
||||
concurrentRoot = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function rerenderConcurrent(el) {
|
||||
const rerenderConcurrent = el => {
|
||||
concurrentRoot.render(el);
|
||||
}
|
||||
};
|
||||
|
||||
runActTests(
|
||||
'concurrent mode',
|
||||
|
@ -50,6 +51,7 @@ describe('ReactTestUtils.act()', () => {
|
|||
unmountConcurrent,
|
||||
rerenderConcurrent,
|
||||
);
|
||||
}
|
||||
|
||||
// and then in sync mode
|
||||
|
||||
|
@ -71,24 +73,26 @@ describe('ReactTestUtils.act()', () => {
|
|||
runActTests('legacy sync mode', renderSync, unmountSync, rerenderSync);
|
||||
|
||||
// and then in batched mode
|
||||
if (__EXPERIMENTAL__) {
|
||||
let batchedRoot = null;
|
||||
function renderBatched(el, dom) {
|
||||
batchedRoot = ReactDOM.unstable_createSyncRoot(dom);
|
||||
const renderBatched = (el, dom) => {
|
||||
batchedRoot = ReactDOM.createSyncRoot(dom);
|
||||
batchedRoot.render(el);
|
||||
}
|
||||
};
|
||||
|
||||
function unmountBatched(dom) {
|
||||
const unmountBatched = dom => {
|
||||
if (batchedRoot !== null) {
|
||||
batchedRoot.unmount();
|
||||
batchedRoot = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function rerenderBatched(el) {
|
||||
const rerenderBatched = el => {
|
||||
batchedRoot.render(el);
|
||||
}
|
||||
};
|
||||
|
||||
runActTests('batched mode', renderBatched, unmountBatched, rerenderBatched);
|
||||
}
|
||||
|
||||
describe('unacted effects', () => {
|
||||
function App() {
|
||||
|
@ -116,11 +120,10 @@ describe('ReactTestUtils.act()', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('warns in batched mode', () => {
|
||||
expect(() => {
|
||||
const root = ReactDOM.unstable_createSyncRoot(
|
||||
document.createElement('div'),
|
||||
);
|
||||
const root = ReactDOM.createSyncRoot(document.createElement('div'));
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
}).toWarnDev([
|
||||
|
@ -131,9 +134,7 @@ describe('ReactTestUtils.act()', () => {
|
|||
|
||||
it('warns in concurrent mode', () => {
|
||||
expect(() => {
|
||||
const root = ReactDOM.unstable_createRoot(
|
||||
document.createElement('div'),
|
||||
);
|
||||
const root = ReactDOM.createRoot(document.createElement('div'));
|
||||
root.render(<App />);
|
||||
Scheduler.unstable_flushAll();
|
||||
}).toWarnDev([
|
||||
|
@ -141,6 +142,7 @@ describe('ReactTestUtils.act()', () => {
|
|||
'An update to App ran an effect, but was not wrapped in act(...)',
|
||||
]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -27,9 +27,10 @@ it('does not warn when rendering in sync mode', () => {
|
|||
}).toWarnDev([]);
|
||||
});
|
||||
|
||||
it('should warn when rendering in concurrent mode', () => {
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('should warn when rendering in concurrent mode', () => {
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createRoot(document.createElement('div')).render(<App />);
|
||||
ReactDOM.createRoot(document.createElement('div')).render(<App />);
|
||||
}).toWarnDev(
|
||||
'In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' +
|
||||
'to guarantee consistent behaviour across tests and browsers.',
|
||||
|
@ -37,15 +38,13 @@ it('should warn when rendering in concurrent mode', () => {
|
|||
);
|
||||
// does not warn twice
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createRoot(document.createElement('div')).render(<App />);
|
||||
ReactDOM.createRoot(document.createElement('div')).render(<App />);
|
||||
}).toWarnDev([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should warn when rendering in batched mode', () => {
|
||||
it('should warn when rendering in batched mode', () => {
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createSyncRoot(document.createElement('div')).render(
|
||||
<App />,
|
||||
);
|
||||
ReactDOM.createSyncRoot(document.createElement('div')).render(<App />);
|
||||
}).toWarnDev(
|
||||
'In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' +
|
||||
'to guarantee consistent behaviour across tests and browsers.',
|
||||
|
@ -53,8 +52,7 @@ it('should warn when rendering in batched mode', () => {
|
|||
);
|
||||
// does not warn twice
|
||||
expect(() => {
|
||||
ReactDOM.unstable_createSyncRoot(document.createElement('div')).render(
|
||||
<App />,
|
||||
);
|
||||
ReactDOM.createSyncRoot(document.createElement('div')).render(<App />);
|
||||
}).toWarnDev([]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1292,6 +1292,7 @@ describe('ReactUpdates', () => {
|
|||
expect(ops).toEqual(['Foo', 'Bar', 'Baz']);
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('delays sync updates inside hidden subtrees in Concurrent Mode', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
|
@ -1323,7 +1324,7 @@ describe('ReactUpdates', () => {
|
|||
);
|
||||
}
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let hiddenDiv;
|
||||
act(() => {
|
||||
root.render(<Foo />);
|
||||
|
@ -1335,7 +1336,11 @@ describe('ReactUpdates', () => {
|
|||
'Foo#effect',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Foo', 'Baz', 'Foo#effect']);
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
'Foo',
|
||||
'Baz',
|
||||
'Foo#effect',
|
||||
]);
|
||||
}
|
||||
hiddenDiv = container.firstChild.firstChild;
|
||||
expect(hiddenDiv.hidden).toBe(true);
|
||||
|
@ -1364,6 +1369,7 @@ describe('ReactUpdates', () => {
|
|||
}
|
||||
expect(hiddenDiv.innerHTML).toBe('<p>bar 1</p>');
|
||||
});
|
||||
}
|
||||
|
||||
it('can render ridiculously large number of roots without triggering infinite update loop error', () => {
|
||||
class Foo extends React.Component {
|
||||
|
|
|
@ -61,7 +61,7 @@ import getComponentName from 'shared/getComponentName';
|
|||
import invariant from 'shared/invariant';
|
||||
import lowPriorityWarningWithoutStack from 'shared/lowPriorityWarningWithoutStack';
|
||||
import warningWithoutStack from 'shared/warningWithoutStack';
|
||||
import {enableStableConcurrentModeAPIs} from 'shared/ReactFeatureFlags';
|
||||
import {exposeConcurrentModeAPIs} from 'shared/ReactFeatureFlags';
|
||||
|
||||
import {
|
||||
getInstanceFromNode,
|
||||
|
@ -593,27 +593,8 @@ const ReactDOM: Object = {
|
|||
|
||||
unstable_batchedUpdates: batchedUpdates,
|
||||
|
||||
// TODO remove this legacy method, unstable_discreteUpdates replaces it
|
||||
unstable_interactiveUpdates: (fn, a, b, c) => {
|
||||
flushDiscreteUpdates();
|
||||
return discreteUpdates(fn, a, b, c);
|
||||
},
|
||||
|
||||
unstable_discreteUpdates: discreteUpdates,
|
||||
unstable_flushDiscreteUpdates: flushDiscreteUpdates,
|
||||
|
||||
flushSync: flushSync,
|
||||
|
||||
unstable_createRoot: createRoot,
|
||||
unstable_createSyncRoot: createSyncRoot,
|
||||
unstable_flushControlled: flushControlled,
|
||||
|
||||
unstable_scheduleHydration(target: Node) {
|
||||
if (target) {
|
||||
queueExplicitHydrationTarget(target);
|
||||
}
|
||||
},
|
||||
|
||||
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
|
||||
// Keep in sync with ReactDOMUnstableNativeDependencies.js
|
||||
// ReactTestUtils.js, and ReactTestUtilsAct.js. This is an array for better minification.
|
||||
|
@ -678,9 +659,19 @@ function warnIfReactDOMContainerInDEV(container) {
|
|||
}
|
||||
}
|
||||
|
||||
if (enableStableConcurrentModeAPIs) {
|
||||
if (exposeConcurrentModeAPIs) {
|
||||
ReactDOM.createRoot = createRoot;
|
||||
ReactDOM.createSyncRoot = createSyncRoot;
|
||||
|
||||
ReactDOM.unstable_discreteUpdates = discreteUpdates;
|
||||
ReactDOM.unstable_flushDiscreteUpdates = flushDiscreteUpdates;
|
||||
ReactDOM.unstable_flushControlled = flushControlled;
|
||||
|
||||
ReactDOM.unstable_scheduleHydration = target => {
|
||||
if (target) {
|
||||
queueExplicitHydrationTarget(target);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const foundDevTools = injectIntoDevTools({
|
||||
|
|
|
@ -474,6 +474,7 @@ describe('ChangeEventPlugin', () => {
|
|||
}
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
describe('concurrent mode', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
@ -486,7 +487,7 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
|
||||
it('text input', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -533,7 +534,7 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
|
||||
it('checkbox input', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -595,7 +596,7 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
|
||||
it('textarea', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let textarea;
|
||||
|
||||
let ops = [];
|
||||
|
@ -642,7 +643,7 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
|
||||
it('parent of input', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -693,7 +694,7 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
|
||||
it('is async for non-input events', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -758,7 +759,7 @@ describe('ChangeEventPlugin', () => {
|
|||
const {act} = TestUtils;
|
||||
const {useState} = React;
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
||||
const target = React.createRef(null);
|
||||
function Foo() {
|
||||
|
@ -789,4 +790,5 @@ describe('ChangeEventPlugin', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -845,6 +845,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
buttonRef.current.dispatchEvent(createEvent('foobar'));
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
it('should work with concurrent mode updates', async () => {
|
||||
const log = [];
|
||||
const TestResponder = createEventResponder({
|
||||
|
@ -865,7 +866,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
);
|
||||
}
|
||||
|
||||
let root = ReactDOM.unstable_createRoot(container);
|
||||
let root = ReactDOM.createRoot(container);
|
||||
root.render(<Test counter={0} />);
|
||||
expect(Scheduler).toFlushAndYield(['Test']);
|
||||
|
||||
|
@ -893,6 +894,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
dispatchClickEvent(ref.current);
|
||||
expect(log).toEqual([{counter: 1}]);
|
||||
});
|
||||
}
|
||||
|
||||
it('should correctly pass through event properties', () => {
|
||||
const timeStamps = [];
|
||||
|
|
|
@ -230,6 +230,7 @@ describe('SimpleEventPlugin', function() {
|
|||
expect(button.textContent).toEqual('Count: 3');
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
describe('interactive events, in concurrent mode', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
@ -241,7 +242,7 @@ describe('SimpleEventPlugin', function() {
|
|||
|
||||
it('flushes pending interactive work before extracting event handler', () => {
|
||||
container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
document.body.appendChild(container);
|
||||
|
||||
let ops = [];
|
||||
|
@ -321,7 +322,7 @@ describe('SimpleEventPlugin', function() {
|
|||
|
||||
it('end result of many interactive updates is deterministic', () => {
|
||||
container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
document.body.appendChild(container);
|
||||
|
||||
let button;
|
||||
|
@ -421,12 +422,14 @@ describe('SimpleEventPlugin', function() {
|
|||
}
|
||||
|
||||
// Initial mount
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<Wrapper />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'High-pri count: 0, Low-pri count: 0',
|
||||
]);
|
||||
expect(button.textContent).toEqual('High-pri count: 0, Low-pri count: 0');
|
||||
expect(button.textContent).toEqual(
|
||||
'High-pri count: 0, Low-pri count: 0',
|
||||
);
|
||||
|
||||
function click() {
|
||||
button.dispatchEvent(
|
||||
|
@ -441,8 +444,12 @@ describe('SimpleEventPlugin', function() {
|
|||
// Click again. This will force the previous discrete update to flush. But
|
||||
// only the high-pri count will increase.
|
||||
click();
|
||||
expect(Scheduler).toHaveYielded(['High-pri count: 1, Low-pri count: 0']);
|
||||
expect(button.textContent).toEqual('High-pri count: 1, Low-pri count: 0');
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'High-pri count: 1, Low-pri count: 0',
|
||||
]);
|
||||
expect(button.textContent).toEqual(
|
||||
'High-pri count: 1, Low-pri count: 0',
|
||||
);
|
||||
|
||||
// Click the button many more times
|
||||
click();
|
||||
|
@ -467,9 +474,12 @@ describe('SimpleEventPlugin', function() {
|
|||
'High-pri count: 8, Low-pri count: 0',
|
||||
'High-pri count: 8, Low-pri count: 8',
|
||||
]);
|
||||
expect(button.textContent).toEqual('High-pri count: 8, Low-pri count: 8');
|
||||
expect(button.textContent).toEqual(
|
||||
'High-pri count: 8, Low-pri count: 8',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('iOS bubbling click fix', function() {
|
||||
// See http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
|
||||
|
|
|
@ -750,9 +750,10 @@ describe('Input event responder', () => {
|
|||
}
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
describe('concurrent mode', () => {
|
||||
it('text input', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -777,7 +778,9 @@ describe('Input event responder', () => {
|
|||
render() {
|
||||
ops.push(`render: ${this.state.value}`);
|
||||
const controlledValue =
|
||||
this.state.value === 'changed' ? 'changed [!]' : this.state.value;
|
||||
this.state.value === 'changed'
|
||||
? 'changed [!]'
|
||||
: this.state.value;
|
||||
return (
|
||||
<Component
|
||||
onChange={this.onChange}
|
||||
|
@ -812,7 +815,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
|
||||
it('checkbox input', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
@ -887,7 +890,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
|
||||
it('textarea', () => {
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let textarea;
|
||||
|
||||
let ops = [];
|
||||
|
@ -912,7 +915,9 @@ describe('Input event responder', () => {
|
|||
render() {
|
||||
ops.push(`render: ${this.state.value}`);
|
||||
const controlledValue =
|
||||
this.state.value === 'changed' ? 'changed [!]' : this.state.value;
|
||||
this.state.value === 'changed'
|
||||
? 'changed [!]'
|
||||
: this.state.value;
|
||||
return (
|
||||
<Component
|
||||
onChange={this.onChange}
|
||||
|
@ -946,6 +951,7 @@ describe('Input event responder', () => {
|
|||
expect(textarea.value).toBe('changed [!]');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('expect displayName to show up for event component', () => {
|
||||
|
|
|
@ -34,6 +34,11 @@ describe('mixing responders with the heritage event system', () => {
|
|||
container = null;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
it('should properly only flush sync once when the event systems are mixed', () => {
|
||||
const useTap = require('react-interactions/events/tap').useTap;
|
||||
const ref = React.createRef();
|
||||
|
@ -66,7 +71,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
}
|
||||
|
||||
const newContainer = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(newContainer);
|
||||
const root = ReactDOM.createRoot(newContainer);
|
||||
document.body.appendChild(newContainer);
|
||||
root.render(<MyComponent />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -137,7 +142,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
}
|
||||
|
||||
const newContainer = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(newContainer);
|
||||
const root = ReactDOM.createRoot(newContainer);
|
||||
document.body.appendChild(newContainer);
|
||||
root.render(<MyComponent />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -216,7 +221,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
|
||||
const newContainer = document.createElement('div');
|
||||
document.body.appendChild(newContainer);
|
||||
const root = ReactDOM.unstable_createRoot(newContainer);
|
||||
const root = ReactDOM.createRoot(newContainer);
|
||||
|
||||
root.render(<MyComponent />);
|
||||
Scheduler.unstable_flushAll();
|
||||
|
@ -238,7 +243,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
const useTap = require('react-interactions/events/tap').useTap;
|
||||
const useInput = require('react-interactions/events/input').useInput;
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
let input;
|
||||
|
||||
let ops = [];
|
||||
|
|
|
@ -2394,7 +2394,7 @@ describe('ReactFresh', () => {
|
|||
});
|
||||
|
||||
it('can hot reload offscreen components', () => {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ && __EXPERIMENTAL__) {
|
||||
const AppV1 = prepare(() => {
|
||||
function Hello() {
|
||||
React.useLayoutEffect(() => {
|
||||
|
@ -2421,7 +2421,7 @@ describe('ReactFresh', () => {
|
|||
};
|
||||
});
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(<AppV1 offscreen={true} />);
|
||||
expect(Scheduler).toFlushAndYieldThrough(['App#layout']);
|
||||
const el = container.firstChild;
|
||||
|
|
|
@ -27,7 +27,6 @@ function loadModules() {
|
|||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffects = false;
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
ReactFeatureFlags.enableSuspenseServerRenderer = true;
|
||||
ReactFeatureFlags.enableProfilerTimer = true;
|
||||
ReactFeatureFlags.enableSchedulerTracing = true;
|
||||
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
|
@ -64,6 +63,11 @@ describe('ReactDOMTracing', () => {
|
|||
loadModules();
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
describe('interaction tracing', () => {
|
||||
describe('hidden', () => {
|
||||
it('traces interaction through hidden subtree', () => {
|
||||
|
@ -101,7 +105,7 @@ describe('ReactDOMTracing', () => {
|
|||
const onRender = jest.fn();
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
SchedulerTracing.unstable_trace('initialization', 0, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
TestUtils.act(() => {
|
||||
|
@ -171,7 +175,7 @@ describe('ReactDOMTracing', () => {
|
|||
const onRender = jest.fn();
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
SchedulerTracing.unstable_trace('initialization', 0, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
|
||||
|
@ -250,7 +254,7 @@ describe('ReactDOMTracing', () => {
|
|||
const onRender = jest.fn();
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
SchedulerTracing.unstable_trace('initialization', 0, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
TestUtils.act(() => {
|
||||
|
@ -344,7 +348,7 @@ describe('ReactDOMTracing', () => {
|
|||
|
||||
const onRender = jest.fn();
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
||||
// Schedule some idle work without any interactions.
|
||||
TestUtils.act(() => {
|
||||
|
@ -448,7 +452,7 @@ describe('ReactDOMTracing', () => {
|
|||
|
||||
const onRender = jest.fn();
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
||||
TestUtils.act(() => {
|
||||
root.render(
|
||||
|
@ -545,7 +549,7 @@ describe('ReactDOMTracing', () => {
|
|||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(container);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
||||
let interaction;
|
||||
|
||||
|
@ -627,7 +631,7 @@ describe('ReactDOMTracing', () => {
|
|||
|
||||
let interaction;
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
const root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
// Hydrate it.
|
||||
SchedulerTracing.unstable_trace('initialization', 0, () => {
|
||||
|
@ -686,7 +690,7 @@ describe('ReactDOMTracing', () => {
|
|||
|
||||
let interaction;
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
const root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
// Start hydrating but simulate blocking for suspense data.
|
||||
suspend = true;
|
||||
|
@ -755,7 +759,7 @@ describe('ReactDOMTracing', () => {
|
|||
|
||||
let interaction;
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(container, {hydrate: true});
|
||||
const root = ReactDOM.createRoot(container, {hydrate: true});
|
||||
|
||||
// Hydrate without suspending to fill in the client-rendered content.
|
||||
suspend = false;
|
||||
|
|
|
@ -54,6 +54,11 @@ describe('ProfilerDOM', () => {
|
|||
return props.text;
|
||||
}
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
it('should correctly trace interactions for async roots', async () => {
|
||||
let resolve;
|
||||
let thenable = {
|
||||
|
@ -75,7 +80,7 @@ describe('ProfilerDOM', () => {
|
|||
}
|
||||
|
||||
const element = document.createElement('div');
|
||||
const root = ReactDOM.unstable_createRoot(element);
|
||||
const root = ReactDOM.createRoot(element);
|
||||
|
||||
let interaction;
|
||||
let wrappedResolve;
|
||||
|
|
|
@ -31,9 +31,9 @@ export const enableProfilerTimer = __PROFILE__;
|
|||
// Trace which interactions trigger each commit.
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
|
||||
// Only used in www builds.
|
||||
export const enableSuspenseServerRenderer = false; // TODO: __DEV__? Here it might just be false.
|
||||
export const enableSelectiveHydration = false;
|
||||
// SSR experiments
|
||||
export const enableSuspenseServerRenderer = __EXPERIMENTAL__;
|
||||
export const enableSelectiveHydration = __EXPERIMENTAL__;
|
||||
|
||||
// Only used in www builds.
|
||||
export const enableSchedulerDebugging = false;
|
||||
|
@ -52,7 +52,7 @@ export const disableInputAttributeSyncing = false;
|
|||
|
||||
// These APIs will no longer be "unstable" in the upcoming 16.7 release,
|
||||
// Control this behavior with a flag to support 16.6 minor releases in the meanwhile.
|
||||
export const enableStableConcurrentModeAPIs = __EXPERIMENTAL__;
|
||||
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
|
||||
|
||||
export const warnAboutShorthandPropertyCollision = false;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ export const enableProfilerTimer = __PROFILE__;
|
|||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const enableSelectiveHydration = false;
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
export const warnAboutShorthandPropertyCollision = false;
|
||||
export const enableSchedulerDebugging = false;
|
||||
export const debugRenderPhaseSideEffectsForStrictMode = true;
|
||||
|
|
|
@ -23,7 +23,7 @@ export const enableSuspenseServerRenderer = false;
|
|||
export const enableSelectiveHydration = false;
|
||||
export const disableJavaScriptURLs = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
export const warnAboutShorthandPropertyCollision = false;
|
||||
export const enableSchedulerDebugging = false;
|
||||
export const enableFlareAPI = false;
|
||||
|
|
|
@ -23,7 +23,7 @@ export const enableSuspenseServerRenderer = false;
|
|||
export const enableSelectiveHydration = false;
|
||||
export const disableJavaScriptURLs = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
export const warnAboutShorthandPropertyCollision = false;
|
||||
export const enableSchedulerDebugging = false;
|
||||
export const enableFlareAPI = false;
|
||||
|
|
|
@ -23,7 +23,7 @@ export const enableSuspenseServerRenderer = false;
|
|||
export const enableSelectiveHydration = false;
|
||||
export const disableJavaScriptURLs = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
export const warnAboutShorthandPropertyCollision = false;
|
||||
export const enableSchedulerDebugging = false;
|
||||
export const enableFlareAPI = false;
|
||||
|
|
|
@ -21,7 +21,7 @@ export const enableProfilerTimer = __PROFILE__;
|
|||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const enableSelectiveHydration = false;
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
export const enableSchedulerDebugging = false;
|
||||
export const disableJavaScriptURLs = false;
|
||||
export const enableFlareAPI = true;
|
||||
|
|
|
@ -39,7 +39,7 @@ export const warnAboutStringRefs = false;
|
|||
export const warnAboutDefaultPropsOnFunctionComponents = false;
|
||||
export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
|
||||
|
||||
export const enableStableConcurrentModeAPIs = false;
|
||||
export const exposeConcurrentModeAPIs = false;
|
||||
|
||||
export const enableSuspenseServerRenderer = true;
|
||||
|
||||
|
|
|
@ -7,7 +7,15 @@ if (NODE_ENV !== 'development' && NODE_ENV !== 'production') {
|
|||
global.__DEV__ = NODE_ENV === 'development';
|
||||
global.__PROFILE__ = NODE_ENV === 'development';
|
||||
global.__UMD__ = false;
|
||||
global.__EXPERIMENTAL__ = process.env.RELEASE_CHANNEL === 'experimental';
|
||||
|
||||
const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL;
|
||||
|
||||
// Default to running tests in experimental mode. If the release channel is
|
||||
// set via an environment variable, then check if it's "experimental".
|
||||
global.__EXPERIMENTAL__ =
|
||||
typeof RELEASE_CHANNEL === 'string'
|
||||
? RELEASE_CHANNEL === 'experimental'
|
||||
: true;
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
global.requestIdleCallback = function(callback) {
|
||||
|
|
|
@ -103,8 +103,8 @@ const getBuildInfo = async () => {
|
|||
join(cwd, 'packages', 'react', 'package.json')
|
||||
);
|
||||
const reactVersion = isExperimental
|
||||
? `${packageJSON.version}-experimental-canary-${commit}`
|
||||
: `${packageJSON.version}-canary-${commit}`;
|
||||
? `${packageJSON.version}-experimental-${commit}`
|
||||
: `${packageJSON.version}-${commit}`;
|
||||
|
||||
return {branch, buildNumber, checksum, commit, reactVersion, version};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue