mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[DevTools] Send Suspense rects to frontend (#34170)
This commit is contained in:
parent
ac7820a99e
commit
de06211dbe
|
|
@ -228,6 +228,8 @@ describe('commit tree', () => {
|
|||
[root]
|
||||
▾ <App>
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
utils.act(() => modernRender(<App renderChildren={true} />));
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
|
|
@ -235,6 +237,8 @@ describe('commit tree', () => {
|
|||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<LazyInnerComponent>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
utils.act(() => modernRender(<App renderChildren={false} />));
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
|
|
@ -299,6 +303,8 @@ describe('commit tree', () => {
|
|||
[root]
|
||||
▾ <App>
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
utils.act(() => modernRender(<App renderChildren={false} />));
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
|
|
|
|||
|
|
@ -24,6 +24,16 @@ describe('Store', () => {
|
|||
let store;
|
||||
let withErrorsOrWarningsIgnored;
|
||||
|
||||
beforeAll(() => {
|
||||
// JSDDOM doesn't implement getClientRects so we're just faking one for testing purposes
|
||||
Element.prototype.getClientRects = function (this: Element) {
|
||||
const textContent = this.textContent;
|
||||
return [
|
||||
new DOMRect(1, 2, textContent.length, textContent.split('\n').length),
|
||||
];
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
global.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
|
|
@ -123,6 +133,8 @@ describe('Store', () => {
|
|||
<Suspense>
|
||||
▾ <Parent>
|
||||
<Child>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -480,6 +492,8 @@ describe('Store', () => {
|
|||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
<Loading>
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={null}>
|
||||
`);
|
||||
|
||||
await act(() => {
|
||||
|
|
@ -491,6 +505,8 @@ describe('Store', () => {
|
|||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
<Component key="Inside">
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={[{x:1,y:2,width:5,height:1}]}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -513,23 +529,31 @@ describe('Store', () => {
|
|||
}) => (
|
||||
<React.Fragment>
|
||||
<Component key="Outside" />
|
||||
<React.Suspense fallback={<Loading key="Parent Fallback" />}>
|
||||
<React.Suspense
|
||||
name="parent"
|
||||
fallback={<Loading key="Parent Fallback" />}>
|
||||
<Component key="Unrelated at Start" />
|
||||
<React.Suspense fallback={<Loading key="Suspense 1 Fallback" />}>
|
||||
<React.Suspense
|
||||
name="one"
|
||||
fallback={<Loading key="Suspense 1 Fallback" />}>
|
||||
{suspendFirst ? (
|
||||
<Never />
|
||||
) : (
|
||||
<Component key="Suspense 1 Content" />
|
||||
)}
|
||||
</React.Suspense>
|
||||
<React.Suspense fallback={<Loading key="Suspense 2 Fallback" />}>
|
||||
<React.Suspense
|
||||
name="two"
|
||||
fallback={<Loading key="Suspense 2 Fallback" />}>
|
||||
{suspendSecond ? (
|
||||
<Never />
|
||||
) : (
|
||||
<Component key="Suspense 2 Content" />
|
||||
)}
|
||||
</React.Suspense>
|
||||
<React.Suspense fallback={<Loading key="Suspense 3 Fallback" />}>
|
||||
<React.Suspense
|
||||
name="three"
|
||||
fallback={<Loading key="Suspense 3 Fallback" />}>
|
||||
<Never />
|
||||
</React.Suspense>
|
||||
{suspendParent && <Never />}
|
||||
|
|
@ -538,7 +562,7 @@ describe('Store', () => {
|
|||
</React.Fragment>
|
||||
);
|
||||
|
||||
await act(() =>
|
||||
await actAsync(() =>
|
||||
render(
|
||||
<Wrapper
|
||||
suspendParent={false}
|
||||
|
|
@ -551,15 +575,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Component key="Suspense 1 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -574,15 +603,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -597,15 +631,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Component key="Suspense 1 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Loading key="Suspense 2 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -620,15 +659,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -643,8 +687,13 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Loading key="Parent Fallback">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -659,15 +708,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Loading key="Suspense 2 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -682,15 +736,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Component key="Suspense 1 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
|
||||
const rendererID = getRendererID();
|
||||
|
|
@ -705,15 +764,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
agent.overrideSuspense({
|
||||
|
|
@ -726,8 +790,13 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Loading key="Parent Fallback">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -742,8 +811,13 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Loading key="Parent Fallback">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
agent.overrideSuspense({
|
||||
|
|
@ -756,15 +830,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Loading key="Suspense 2 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
agent.overrideSuspense({
|
||||
|
|
@ -777,15 +856,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Loading key="Suspense 1 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Loading key="Suspense 2 Fallback">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}, {x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
await act(() =>
|
||||
render(
|
||||
|
|
@ -800,15 +884,20 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <Wrapper>
|
||||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="parent">
|
||||
<Component key="Unrelated at Start">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="one">
|
||||
<Component key="Suspense 1 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="two">
|
||||
<Component key="Suspense 2 Content">
|
||||
▾ <Suspense>
|
||||
▾ <Suspense name="three">
|
||||
<Loading key="Suspense 3 Fallback">
|
||||
<Component key="Unrelated at End">
|
||||
[shell]
|
||||
<Suspense name="parent" rects={[{x:1,y:2,width:10,height:1}]}>
|
||||
<Suspense name="one" rects={null}>
|
||||
<Suspense name="two" rects={null}>
|
||||
<Suspense name="three" rects={null}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -848,6 +937,8 @@ describe('Store', () => {
|
|||
<Component key="A">
|
||||
▾ <Suspense>
|
||||
<Loading>
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={null}>
|
||||
`);
|
||||
|
||||
await act(() => {
|
||||
|
|
@ -861,6 +952,8 @@ describe('Store', () => {
|
|||
▾ <Suspense>
|
||||
<Component key="B">
|
||||
<Component key="C">
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={[{x:1,y:2,width:5,height:1}]}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -1197,6 +1290,8 @@ describe('Store', () => {
|
|||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▸ <Wrapper>
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={null}>
|
||||
`);
|
||||
|
||||
// This test isn't meaningful unless we expand the suspended tree
|
||||
|
|
@ -1212,6 +1307,8 @@ describe('Store', () => {
|
|||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
<Loading>
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={null}>
|
||||
`);
|
||||
|
||||
await act(() => {
|
||||
|
|
@ -1223,6 +1320,8 @@ describe('Store', () => {
|
|||
<Component key="Outside">
|
||||
▾ <Suspense>
|
||||
<Component key="Inside">
|
||||
[shell]
|
||||
<Suspense name="Wrapper>?" rects={[{x:1,y:2,width:5,height:1}]}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -1447,6 +1546,8 @@ describe('Store', () => {
|
|||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▸ <SuspenseTree>
|
||||
[shell]
|
||||
<Suspense name="SuspenseTree>?" rects={null}>
|
||||
`);
|
||||
|
||||
await act(() =>
|
||||
|
|
@ -1460,6 +1561,8 @@ describe('Store', () => {
|
|||
▾ <SuspenseTree>
|
||||
▾ <Suspense>
|
||||
▸ <Parent>
|
||||
[shell]
|
||||
<Suspense name="SuspenseTree>?" rects={null}>
|
||||
`);
|
||||
|
||||
const rendererID = getRendererID();
|
||||
|
|
@ -1477,6 +1580,8 @@ describe('Store', () => {
|
|||
▾ <SuspenseTree>
|
||||
▾ <Suspense>
|
||||
<Fallback>
|
||||
[shell]
|
||||
<Suspense name="SuspenseTree>?" rects={null}>
|
||||
`);
|
||||
|
||||
await act(() =>
|
||||
|
|
@ -1491,6 +1596,8 @@ describe('Store', () => {
|
|||
▾ <SuspenseTree>
|
||||
▾ <Suspense>
|
||||
▸ <Parent>
|
||||
[shell]
|
||||
<Suspense name="SuspenseTree>?" rects={null}>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
@ -1794,6 +1901,8 @@ describe('Store', () => {
|
|||
[root]
|
||||
▾ <App>
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
|
||||
await Promise.resolve();
|
||||
|
|
@ -1806,6 +1915,8 @@ describe('Store', () => {
|
|||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<LazyInnerComponent>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
|
||||
// Render again to unmount it
|
||||
|
|
@ -2291,20 +2402,24 @@ describe('Store', () => {
|
|||
await actAsync(() => render(<App renderA={true} />));
|
||||
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<ChildA>
|
||||
`);
|
||||
[root]
|
||||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<ChildA>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
|
||||
await actAsync(() => render(<App renderA={false} />));
|
||||
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<ChildB>
|
||||
`);
|
||||
[root]
|
||||
▾ <App>
|
||||
▾ <Suspense>
|
||||
<ChildB>
|
||||
[shell]
|
||||
<Suspense name="App>?" rects={null}>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ describe('Store component filters', () => {
|
|||
<div>
|
||||
▾ <Suspense>
|
||||
<div>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
`);
|
||||
|
||||
await actAsync(
|
||||
|
|
@ -171,6 +174,9 @@ describe('Store component filters', () => {
|
|||
<div>
|
||||
▾ <Suspense>
|
||||
<div>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
`);
|
||||
|
||||
await actAsync(
|
||||
|
|
@ -186,6 +192,9 @@ describe('Store component filters', () => {
|
|||
<div>
|
||||
▾ <Suspense>
|
||||
<div>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
<Suspense name="Unknown" rects={[]}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe('StoreStressConcurrent', () => {
|
|||
// this helper with the real thing.
|
||||
actAsync = require('./utils').actAsync;
|
||||
|
||||
print = require('./__serializers__/storeSerializer').print;
|
||||
print = require('./__serializers__/storeSerializer').printStore;
|
||||
});
|
||||
|
||||
// This is a stress test for the tree mount/update/unmount traversal.
|
||||
|
|
@ -67,8 +67,7 @@ describe('StoreStressConcurrent', () => {
|
|||
let container = document.createElement('div');
|
||||
let root = ReactDOMClient.createRoot(container);
|
||||
act(() => root.render(<Parent>{[a, b, c, d, e]}</Parent>));
|
||||
expect(store).toMatchInlineSnapshot(
|
||||
`
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
|
|
@ -76,8 +75,7 @@ describe('StoreStressConcurrent', () => {
|
|||
<C key="c">
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`,
|
||||
);
|
||||
`);
|
||||
expect(container.textContent).toMatch('abcde');
|
||||
const snapshotForABCDE = print(store);
|
||||
|
||||
|
|
@ -86,8 +84,7 @@ describe('StoreStressConcurrent', () => {
|
|||
act(() => {
|
||||
setShowX(true);
|
||||
});
|
||||
expect(store).toMatchInlineSnapshot(
|
||||
`
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <Parent>
|
||||
<A key="a">
|
||||
|
|
@ -96,8 +93,7 @@ describe('StoreStressConcurrent', () => {
|
|||
<X>
|
||||
<D key="d">
|
||||
<E key="e">
|
||||
`,
|
||||
);
|
||||
`);
|
||||
expect(container.textContent).toMatch('abxde');
|
||||
const snapshotForABXDE = print(store);
|
||||
|
||||
|
|
@ -419,7 +415,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.d
|
||||
snapshots.push(print(store));
|
||||
snapshots.push(print(store, false, null, false));
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
|
@ -524,7 +520,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
|
@ -544,7 +540,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -556,7 +552,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -567,7 +563,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -593,7 +589,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -609,7 +605,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -624,7 +620,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -646,7 +642,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -662,7 +658,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -673,7 +669,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -699,7 +695,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -711,7 +707,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -726,7 +722,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -755,7 +751,7 @@ describe('StoreStressConcurrent', () => {
|
|||
const suspenseID = store.getElementIDAtIndex(2);
|
||||
|
||||
// Force fallback.
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
await actAsync(async () => {
|
||||
bridge.send('overrideSuspense', {
|
||||
id: suspenseID,
|
||||
|
|
@ -763,7 +759,7 @@ describe('StoreStressConcurrent', () => {
|
|||
forceFallback: true,
|
||||
});
|
||||
});
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
|
||||
// Stop forcing fallback.
|
||||
await actAsync(async () => {
|
||||
|
|
@ -773,7 +769,7 @@ describe('StoreStressConcurrent', () => {
|
|||
forceFallback: false,
|
||||
});
|
||||
});
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
|
||||
// Trigger actual fallback.
|
||||
await act(() =>
|
||||
|
|
@ -789,7 +785,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
|
||||
// Force fallback while we're in fallback mode.
|
||||
await act(() => {
|
||||
|
|
@ -800,7 +796,7 @@ describe('StoreStressConcurrent', () => {
|
|||
});
|
||||
});
|
||||
// Keep seeing fallback content.
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
|
||||
// Switch to primary mode.
|
||||
await act(() =>
|
||||
|
|
@ -813,7 +809,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Fallback is still forced though.
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
|
||||
// Stop forcing fallback. This reverts to primary content.
|
||||
await actAsync(async () => {
|
||||
|
|
@ -824,7 +820,7 @@ describe('StoreStressConcurrent', () => {
|
|||
});
|
||||
});
|
||||
// Now we see primary content.
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
|
||||
// Clean up after every iteration.
|
||||
await actAsync(async () => root.unmount());
|
||||
|
|
@ -910,7 +906,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
snapshots.push(print(store));
|
||||
snapshots.push(print(store, false, null, false));
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
|
@ -935,7 +931,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// We snapshot each step once so it doesn't regress.
|
||||
fallbackSnapshots.push(print(store));
|
||||
fallbackSnapshots.push(print(store, false, null, false));
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
}
|
||||
|
|
@ -1065,7 +1061,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1079,7 +1075,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1092,7 +1088,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -1121,7 +1117,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(fallbackSnapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1140,7 +1136,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1158,7 +1154,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(fallbackSnapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -1182,7 +1178,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1196,7 +1192,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1209,7 +1205,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -1233,7 +1229,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(fallbackSnapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[i]);
|
||||
// Re-render with steps[j].
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1247,7 +1243,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Verify the successful transition to steps[j].
|
||||
expect(print(store)).toEqual(snapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[j]);
|
||||
// Check that we can transition back again.
|
||||
await act(() =>
|
||||
root.render(
|
||||
|
|
@ -1260,7 +1256,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(fallbackSnapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[i]);
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
expect(print(store)).toBe('');
|
||||
|
|
@ -1291,7 +1287,7 @@ describe('StoreStressConcurrent', () => {
|
|||
const suspenseID = store.getElementIDAtIndex(2);
|
||||
|
||||
// Force fallback.
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
await actAsync(async () => {
|
||||
bridge.send('overrideSuspense', {
|
||||
id: suspenseID,
|
||||
|
|
@ -1299,7 +1295,7 @@ describe('StoreStressConcurrent', () => {
|
|||
forceFallback: true,
|
||||
});
|
||||
});
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
|
||||
// Stop forcing fallback.
|
||||
await actAsync(async () => {
|
||||
|
|
@ -1309,7 +1305,7 @@ describe('StoreStressConcurrent', () => {
|
|||
forceFallback: false,
|
||||
});
|
||||
});
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
|
||||
// Trigger actual fallback.
|
||||
await act(() =>
|
||||
|
|
@ -1323,7 +1319,7 @@ describe('StoreStressConcurrent', () => {
|
|||
</Root>,
|
||||
),
|
||||
);
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
|
||||
// Force fallback while we're in fallback mode.
|
||||
await act(() => {
|
||||
|
|
@ -1334,7 +1330,7 @@ describe('StoreStressConcurrent', () => {
|
|||
});
|
||||
});
|
||||
// Keep seeing fallback content.
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
|
||||
// Switch to primary mode.
|
||||
await act(() =>
|
||||
|
|
@ -1349,7 +1345,7 @@ describe('StoreStressConcurrent', () => {
|
|||
),
|
||||
);
|
||||
// Fallback is still forced though.
|
||||
expect(print(store)).toEqual(fallbackSnapshots[j]);
|
||||
expect(print(store, false, null, false)).toEqual(fallbackSnapshots[j]);
|
||||
|
||||
// Stop forcing fallback. This reverts to primary content.
|
||||
await actAsync(async () => {
|
||||
|
|
@ -1360,7 +1356,7 @@ describe('StoreStressConcurrent', () => {
|
|||
});
|
||||
});
|
||||
// Now we see primary content.
|
||||
expect(print(store)).toEqual(snapshots[i]);
|
||||
expect(print(store, false, null, false)).toEqual(snapshots[i]);
|
||||
|
||||
// Clean up after every iteration.
|
||||
await act(() => root.unmount());
|
||||
|
|
|
|||
|
|
@ -1368,6 +1368,9 @@ describe('TreeListContext', () => {
|
|||
▾ <Child>
|
||||
▾ <Suspense>
|
||||
<Grandchild>
|
||||
[shell]
|
||||
<Suspense name="Parent>?" rects={null}>
|
||||
<Suspense name="Child>?" rects={null}>
|
||||
`);
|
||||
|
||||
const outerSuspenseID = ((store.getElementIDAtIndex(1): any): number);
|
||||
|
|
@ -1407,6 +1410,9 @@ describe('TreeListContext', () => {
|
|||
▾ <Child>
|
||||
▾ <Suspense>
|
||||
<Grandchild>
|
||||
[shell]
|
||||
<Suspense name="Parent>?" rects={null}>
|
||||
<Suspense name="Child>?" rects={null}>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
@ -2361,16 +2367,20 @@ describe('TreeListContext', () => {
|
|||
jest.runAllTimers();
|
||||
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
<Suspense>
|
||||
`);
|
||||
[root]
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
|
||||
selectNextErrorOrWarning();
|
||||
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
<Suspense>
|
||||
`);
|
||||
[root]
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should properly handle errors/warnings from components that dont mount because of Suspense', async () => {
|
||||
|
|
@ -2392,9 +2402,11 @@ describe('TreeListContext', () => {
|
|||
utils.act(() => TestRenderer.create(<Contexts />));
|
||||
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
<Suspense>
|
||||
`);
|
||||
[root]
|
||||
<Suspense>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
|
||||
await Promise.resolve();
|
||||
withErrorsOrWarningsIgnored(['test-only:'], () =>
|
||||
|
|
@ -2414,6 +2426,8 @@ describe('TreeListContext', () => {
|
|||
▾ <Suspense>
|
||||
<Child> ⚠
|
||||
<Child>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
});
|
||||
|
||||
|
|
@ -2442,6 +2456,8 @@ describe('TreeListContext', () => {
|
|||
▾ <Suspense>
|
||||
▾ <Fallback>
|
||||
<Child> ✕
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
|
||||
await Promise.resolve();
|
||||
|
|
@ -2456,10 +2472,12 @@ describe('TreeListContext', () => {
|
|||
);
|
||||
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <Suspense>
|
||||
<Child>
|
||||
`);
|
||||
[root]
|
||||
▾ <Suspense>
|
||||
<Child>
|
||||
[shell]
|
||||
<Suspense name="Unknown" rects={null}>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ import {
|
|||
SUSPENSE_TREE_OPERATION_ADD,
|
||||
SUSPENSE_TREE_OPERATION_REMOVE,
|
||||
SUSPENSE_TREE_OPERATION_REORDER_CHILDREN,
|
||||
SUSPENSE_TREE_OPERATION_RESIZE,
|
||||
} from '../../constants';
|
||||
import {inspectHooksOfFiber} from 'react-debug-tools';
|
||||
import {
|
||||
|
|
@ -2558,6 +2559,20 @@ export function attach(
|
|||
pushOperation(fiberID);
|
||||
pushOperation(parentID);
|
||||
pushOperation(nameStringID);
|
||||
|
||||
const rects = suspenseInstance.rects;
|
||||
if (rects === null) {
|
||||
pushOperation(-1);
|
||||
} else {
|
||||
pushOperation(rects.length);
|
||||
for (let i = 0; i < rects.length; ++i) {
|
||||
const rect = rects[i];
|
||||
pushOperation(Math.round(rect.x));
|
||||
pushOperation(Math.round(rect.y));
|
||||
pushOperation(Math.round(rect.width));
|
||||
pushOperation(Math.round(rect.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function recordUnmount(fiberInstance: FiberInstance): void {
|
||||
|
|
@ -2606,7 +2621,30 @@ export function attach(
|
|||
}
|
||||
|
||||
function recordSuspenseResize(suspenseNode: SuspenseNode): void {
|
||||
// TODO: Notify the front end of the change.
|
||||
if (__DEBUG__) {
|
||||
console.log('recordSuspenseResize()', suspenseNode);
|
||||
}
|
||||
const fiberInstance = suspenseNode.instance;
|
||||
if (fiberInstance.kind !== FIBER_INSTANCE) {
|
||||
// TODO: Resizes of filtered Suspense nodes are currently dropped.
|
||||
return;
|
||||
}
|
||||
|
||||
pushOperation(SUSPENSE_TREE_OPERATION_RESIZE);
|
||||
pushOperation(fiberInstance.id);
|
||||
const rects = suspenseNode.rects;
|
||||
if (rects === null) {
|
||||
pushOperation(-1);
|
||||
} else {
|
||||
pushOperation(rects.length);
|
||||
for (let i = 0; i < rects.length; ++i) {
|
||||
const rect = rects[i];
|
||||
pushOperation(Math.round(rect.x));
|
||||
pushOperation(Math.round(rect.y));
|
||||
pushOperation(Math.round(rect.width));
|
||||
pushOperation(Math.round(rect.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function recordSuspenseUnmount(suspenseInstance: SuspenseNode): void {
|
||||
|
|
@ -3442,7 +3480,25 @@ export function attach(
|
|||
// Measure this Suspense node. In general we shouldn't do this until we have
|
||||
// inserted the new children but since we know this is a FiberInstance we'll
|
||||
// just use the Fiber anyway.
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
// Fallbacks get attributed to the parent so we only measure if we're
|
||||
// showing primary content.
|
||||
if (OffscreenComponent === -1) {
|
||||
const isTimedOut = fiber.memoizedState !== null;
|
||||
if (!isTimedOut) {
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
}
|
||||
} else {
|
||||
const contentFiber = fiber.child;
|
||||
if (contentFiber === null) {
|
||||
throw new Error(
|
||||
'There should always be an Offscreen Fiber child in a Suspense boundary.',
|
||||
);
|
||||
}
|
||||
const isTimedOut = fiber.memoizedState !== null;
|
||||
if (!isTimedOut) {
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
}
|
||||
}
|
||||
recordSuspenseMount(newSuspenseNode, reconcilingParentSuspenseNode);
|
||||
}
|
||||
insertChild(newInstance);
|
||||
|
|
@ -3476,7 +3532,25 @@ export function attach(
|
|||
// Measure this Suspense node. In general we shouldn't do this until we have
|
||||
// inserted the new children but since we know this is a FiberInstance we'll
|
||||
// just use the Fiber anyway.
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
// Fallbacks get attributed to the parent so we only measure if we're
|
||||
// showing primary content.
|
||||
if (OffscreenComponent === -1) {
|
||||
const isTimedOut = fiber.memoizedState !== null;
|
||||
if (!isTimedOut) {
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
}
|
||||
} else {
|
||||
const contentFiber = fiber.child;
|
||||
if (contentFiber === null) {
|
||||
throw new Error(
|
||||
'There should always be an Offscreen Fiber child in a Suspense boundary.',
|
||||
);
|
||||
}
|
||||
const isTimedOut = fiber.memoizedState !== null;
|
||||
if (!isTimedOut) {
|
||||
newSuspenseNode.rects = measureInstance(newInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
insertChild(newInstance);
|
||||
if (__DEBUG__) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export const TREE_OPERATION_SET_SUBTREE_MODE = 7;
|
|||
export const SUSPENSE_TREE_OPERATION_ADD = 8;
|
||||
export const SUSPENSE_TREE_OPERATION_REMOVE = 9;
|
||||
export const SUSPENSE_TREE_OPERATION_REORDER_CHILDREN = 10;
|
||||
export const SUSPENSE_TREE_OPERATION_RESIZE = 11;
|
||||
|
||||
export const PROFILING_FLAG_BASIC_SUPPORT = 0b01;
|
||||
export const PROFILING_FLAG_TIMELINE_SUPPORT = 0b10;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
SUSPENSE_TREE_OPERATION_ADD,
|
||||
SUSPENSE_TREE_OPERATION_REMOVE,
|
||||
SUSPENSE_TREE_OPERATION_REORDER_CHILDREN,
|
||||
SUSPENSE_TREE_OPERATION_RESIZE,
|
||||
} from '../constants';
|
||||
import {ElementTypeRoot} from '../frontend/types';
|
||||
import {
|
||||
|
|
@ -1418,6 +1419,7 @@ export default class Store extends EventEmitter<{
|
|||
const id = operations[i + 1];
|
||||
const parentID = operations[i + 2];
|
||||
const nameStringID = operations[i + 3];
|
||||
const numRects = ((operations[i + 4]: any): number);
|
||||
let name = stringTable[nameStringID];
|
||||
|
||||
if (this._idToSuspense.has(id)) {
|
||||
|
|
@ -1448,6 +1450,22 @@ export default class Store extends EventEmitter<{
|
|||
}
|
||||
}
|
||||
|
||||
i += 5;
|
||||
let rects: SuspenseNode['rects'];
|
||||
if (numRects === -1) {
|
||||
rects = null;
|
||||
} else {
|
||||
rects = [];
|
||||
for (let rectIndex = 0; rectIndex < numRects; rectIndex++) {
|
||||
const x = operations[i + 0];
|
||||
const y = operations[i + 1];
|
||||
const width = operations[i + 2];
|
||||
const height = operations[i + 3];
|
||||
rects.push({x, y, width, height});
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEBUG__) {
|
||||
debug('Suspense Add', `node ${id} as child of ${parentID}`);
|
||||
}
|
||||
|
|
@ -1476,10 +1494,9 @@ export default class Store extends EventEmitter<{
|
|||
parentID,
|
||||
children: [],
|
||||
name,
|
||||
rects,
|
||||
});
|
||||
|
||||
i += 4;
|
||||
|
||||
hasSuspenseTreeChanged = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1591,6 +1608,61 @@ export default class Store extends EventEmitter<{
|
|||
hasSuspenseTreeChanged = true;
|
||||
break;
|
||||
}
|
||||
case SUSPENSE_TREE_OPERATION_RESIZE: {
|
||||
const id = ((operations[i + 1]: any): number);
|
||||
const numRects = ((operations[i + 2]: any): number);
|
||||
i += 3;
|
||||
|
||||
const suspense = this._idToSuspense.get(id);
|
||||
if (suspense === undefined) {
|
||||
this._throwAndEmitError(
|
||||
Error(
|
||||
`Cannot set rects for suspense node "${id}" because no matching node was found in the Store.`,
|
||||
),
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
let nextRects: SuspenseNode['rects'];
|
||||
if (numRects === -1) {
|
||||
nextRects = null;
|
||||
} else {
|
||||
nextRects = [];
|
||||
for (let rectIndex = 0; rectIndex < numRects; rectIndex++) {
|
||||
const x = operations[i + 0];
|
||||
const y = operations[i + 1];
|
||||
const width = operations[i + 2];
|
||||
const height = operations[i + 3];
|
||||
|
||||
nextRects.push({x, y, width, height});
|
||||
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
|
||||
suspense.rects = nextRects;
|
||||
|
||||
if (__DEBUG__) {
|
||||
debug(
|
||||
'Resize',
|
||||
`Suspense node ${id} resize to ${
|
||||
nextRects === null
|
||||
? 'null'
|
||||
: nextRects
|
||||
.map(
|
||||
rect =>
|
||||
`(${rect.x},${rect.y},${rect.width},${rect.height})`,
|
||||
)
|
||||
.join(',')
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
hasSuspenseTreeChanged = true;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this._throwAndEmitError(
|
||||
new UnsupportedBridgeOperationError(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@
|
|||
import JSON5 from 'json5';
|
||||
|
||||
import type {ReactFunctionLocation} from 'shared/ReactTypes';
|
||||
import type {Element} from 'react-devtools-shared/src/frontend/types';
|
||||
import type {
|
||||
Element,
|
||||
SuspenseNode,
|
||||
} from 'react-devtools-shared/src/frontend/types';
|
||||
import type {StateContext} from './views/Components/TreeContext';
|
||||
import type Store from './store';
|
||||
|
||||
|
|
@ -28,6 +31,11 @@ export function printElement(
|
|||
key = ` key="${element.key}"`;
|
||||
}
|
||||
|
||||
let name = '';
|
||||
if (element.nameProp !== null) {
|
||||
name = ` name="${element.nameProp}"`;
|
||||
}
|
||||
|
||||
let hocDisplayNames = null;
|
||||
if (element.hocDisplayNames !== null) {
|
||||
hocDisplayNames = [...element.hocDisplayNames];
|
||||
|
|
@ -43,7 +51,45 @@ export function printElement(
|
|||
|
||||
return `${' '.repeat(element.depth + 1)}${prefix} <${
|
||||
element.displayName || 'null'
|
||||
}${key}>${hocs}${suffix}`;
|
||||
}${key}${name}>${hocs}${suffix}`;
|
||||
}
|
||||
|
||||
function printSuspense(
|
||||
suspense: SuspenseNode,
|
||||
includeWeight: boolean = false,
|
||||
): string {
|
||||
let name = '';
|
||||
if (suspense.name !== null) {
|
||||
name = ` name="${suspense.name}"`;
|
||||
}
|
||||
|
||||
let printedRects = '';
|
||||
const rects = suspense.rects;
|
||||
if (rects === null) {
|
||||
printedRects = ' rects={null}';
|
||||
} else {
|
||||
printedRects = ` rects={[${rects.map(rect => `{x:${rect.x},y:${rect.y},width:${rect.width},height:${rect.height}}`).join(', ')}]}`;
|
||||
}
|
||||
|
||||
return `<Suspense${name}${printedRects}>`;
|
||||
}
|
||||
|
||||
function printSuspenseWithChildren(
|
||||
store: Store,
|
||||
suspense: SuspenseNode,
|
||||
depth: number,
|
||||
): Array<string> {
|
||||
const lines = [' '.repeat(depth) + printSuspense(suspense)];
|
||||
for (let i = 0; i < suspense.children.length; i++) {
|
||||
const childID = suspense.children[i];
|
||||
const child = store.getSuspenseByID(childID);
|
||||
if (child === null) {
|
||||
throw new Error(`Could not find Suspense node with ID "${childID}".`);
|
||||
}
|
||||
lines.push(...printSuspenseWithChildren(store, child, depth + 1));
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function printOwnersList(
|
||||
|
|
@ -59,6 +105,7 @@ export function printStore(
|
|||
store: Store,
|
||||
includeWeight: boolean = false,
|
||||
state: StateContext | null = null,
|
||||
includeSuspense: boolean = true,
|
||||
): string {
|
||||
const snapshotLines = [];
|
||||
|
||||
|
|
@ -129,6 +176,26 @@ export function printStore(
|
|||
}
|
||||
|
||||
rootWeight += weight;
|
||||
|
||||
if (includeSuspense) {
|
||||
const shell = store.getSuspenseByID(rootID);
|
||||
// Roots from legacy renderers don't have a separate Suspense tree
|
||||
if (shell !== null) {
|
||||
if (shell.children.length > 0) {
|
||||
snapshotLines.push('[shell]');
|
||||
for (let i = 0; i < shell.children.length; i++) {
|
||||
const childID = shell.children[i];
|
||||
const child = store.getSuspenseByID(childID);
|
||||
if (child === null) {
|
||||
throw new Error(
|
||||
`Could not find Suspense node with ID "${childID}".`,
|
||||
);
|
||||
}
|
||||
snapshotLines.push(...printSuspenseWithChildren(store, child, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the pretty-printed test align with the Store's reported number of total rows.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
SUSPENSE_TREE_OPERATION_ADD,
|
||||
SUSPENSE_TREE_OPERATION_REMOVE,
|
||||
SUSPENSE_TREE_OPERATION_REORDER_CHILDREN,
|
||||
SUSPENSE_TREE_OPERATION_RESIZE,
|
||||
} from 'react-devtools-shared/src/constants';
|
||||
import {
|
||||
parseElementDisplayNameFromBackend,
|
||||
|
|
@ -376,16 +377,26 @@ function updateTree(
|
|||
const fiberID = operations[i + 1];
|
||||
const parentID = operations[i + 2];
|
||||
const nameStringID = operations[i + 3];
|
||||
const numRects = operations[i + 4];
|
||||
const name = stringTable[nameStringID];
|
||||
|
||||
i += 4;
|
||||
|
||||
if (__DEBUG__) {
|
||||
let rects: string;
|
||||
if (numRects === -1) {
|
||||
rects = 'null';
|
||||
} else {
|
||||
rects =
|
||||
'[' +
|
||||
operations.slice(i + 5, i + 5 + numRects * 4).join(',') +
|
||||
']';
|
||||
}
|
||||
debug(
|
||||
'Add suspense',
|
||||
`node ${fiberID} (${String(name)}) under ${parentID}`,
|
||||
`node ${fiberID} (name=${JSON.stringify(name)}, rects={${rects}}) under ${parentID}`,
|
||||
);
|
||||
}
|
||||
|
||||
i += 5 + (numRects === -1 ? 0 : numRects * 4);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -416,6 +427,30 @@ function updateTree(
|
|||
break;
|
||||
}
|
||||
|
||||
case SUSPENSE_TREE_OPERATION_RESIZE: {
|
||||
const suspenseID = ((operations[i + 1]: any): number);
|
||||
const numRects = ((operations[i + 2]: any): number);
|
||||
|
||||
if (__DEBUG__) {
|
||||
if (numRects === -1) {
|
||||
debug('Suspense resize', `suspense ${suspenseID} rects null`);
|
||||
} else {
|
||||
const rects = ((operations.slice(
|
||||
i + 3,
|
||||
i + 3 + numRects * 4,
|
||||
): any): Array<number>);
|
||||
debug(
|
||||
'Suspense resize',
|
||||
`suspense ${suspenseID} rects [${rects.join(',')}]`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
i += 3 + (numRects === -1 ? 0 : numRects * 4);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw Error(`Unsupported Bridge operation "${operation}"`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,11 +185,19 @@ export type Element = {
|
|||
compiledWithForget: boolean,
|
||||
};
|
||||
|
||||
export type Rect = {
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
};
|
||||
|
||||
export type SuspenseNode = {
|
||||
id: Element['id'],
|
||||
parentID: SuspenseNode['id'] | 0,
|
||||
children: Array<SuspenseNode['id']>,
|
||||
name: string | null,
|
||||
rects: null | Array<Rect>,
|
||||
};
|
||||
|
||||
// Serialized version of ReactIOInfo
|
||||
|
|
|
|||
55
packages/react-devtools-shared/src/utils.js
vendored
55
packages/react-devtools-shared/src/utils.js
vendored
|
|
@ -43,6 +43,7 @@ import {
|
|||
SUSPENSE_TREE_OPERATION_ADD,
|
||||
SUSPENSE_TREE_OPERATION_REMOVE,
|
||||
SUSPENSE_TREE_OPERATION_REORDER_CHILDREN,
|
||||
SUSPENSE_TREE_OPERATION_RESIZE,
|
||||
} from './constants';
|
||||
import {
|
||||
ComponentFilterElementType,
|
||||
|
|
@ -339,11 +340,34 @@ export function printOperationsArray(operations: Array<number>) {
|
|||
const parentID = operations[i + 2];
|
||||
const nameStringID = operations[i + 3];
|
||||
const name = stringTable[nameStringID];
|
||||
const numRects = operations[i + 4];
|
||||
|
||||
i += 4;
|
||||
i += 5;
|
||||
|
||||
let rects: string;
|
||||
if (numRects === -1) {
|
||||
rects = 'null';
|
||||
} else {
|
||||
rects = '[';
|
||||
for (let rectIndex = 0; rectIndex < numRects; rectIndex++) {
|
||||
const offset = i + rectIndex * 4;
|
||||
const x = operations[offset + 0];
|
||||
const y = operations[offset + 1];
|
||||
const width = operations[offset + 2];
|
||||
const height = operations[offset + 3];
|
||||
|
||||
if (rectIndex > 0) {
|
||||
rects += ', ';
|
||||
}
|
||||
rects += `(${x}, ${y}, ${width}, ${height})`;
|
||||
|
||||
i += 4;
|
||||
}
|
||||
rects += ']';
|
||||
}
|
||||
|
||||
logs.push(
|
||||
`Add suspense node ${fiberID} (${String(name)}) under ${parentID}`,
|
||||
`Add suspense node ${fiberID} (${String(name)},rects={${rects}}) under ${parentID}`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -372,6 +396,33 @@ export function printOperationsArray(operations: Array<number>) {
|
|||
);
|
||||
break;
|
||||
}
|
||||
case SUSPENSE_TREE_OPERATION_RESIZE: {
|
||||
const id = ((operations[i + 1]: any): number);
|
||||
const numRects = ((operations[i + 2]: any): number);
|
||||
i += 3;
|
||||
|
||||
if (numRects === -1) {
|
||||
logs.push(`Resize suspense node ${id} to null`);
|
||||
} else {
|
||||
let line = `Resize suspense node ${id} to [`;
|
||||
for (let rectIndex = 0; rectIndex < numRects; rectIndex++) {
|
||||
const x = operations[i + 0];
|
||||
const y = operations[i + 1];
|
||||
const width = operations[i + 2];
|
||||
const height = operations[i + 3];
|
||||
|
||||
if (rectIndex > 0) {
|
||||
line += ', ';
|
||||
}
|
||||
line += `(${x}, ${y}, ${width}, ${height})`;
|
||||
|
||||
i += 4;
|
||||
}
|
||||
logs.push(line + ']');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error(`Unsupported Bridge operation "${operation}"`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user