/*** Copyright (c) Meta Platforms, Inc. and affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.** @flow*/describe('Store (legacy)', () => {
let React;
let ReactDOM;
let store;
const act = (callback: Function) => {
callback();
jest.runAllTimers(); // Flush Bridge operations
};beforeEach(() => {
store = global.store;
// Redirect all React/ReactDOM requires to the v15 UMD.
// We use the UMD because Jest doesn't enable us to mock deep imports (e.g. "react/lib/Something").
jest.mock('react', () => jest.requireActual('react-15/dist/react.js'));
jest.mock('react-dom', () =>
jest.requireActual('react-dom-15/dist/react-dom.js'),
);React = require('react');
ReactDOM = require('react-dom');
});it('should not allow a root node to be collapsed', () => {
const Component = () => <div>Hi</div>;
act(() =>ReactDOM.render(<Component count={4} />, document.createElement('div')),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Component><div>`);expect(store.roots).toHaveLength(1);
const rootID = store.roots[0];
expect(() => store.toggleIsCollapsed(rootID, true)).toThrow(
'Root nodes cannot be collapsed',);});describe('collapseNodesByDefault:false', () => {beforeEach(() => {store.collapseNodesByDefault = false;
});it('should support mount and update operations', () => {const Grandparent = ({count}) => (<div><Parent count={count} /><Parent count={count} /></div>);const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;const container = document.createElement('div');
act(() => ReactDOM.render(<Grandparent count={4} />, container));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Child key="2"><div>▾ <Child key="3"><div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Child key="2"><div>▾ <Child key="3"><div>`);act(() => ReactDOM.render(<Grandparent count={2} />, container));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>`);act(() => ReactDOM.unmountComponentAtNode(container));
expect(store).toMatchInlineSnapshot(``);
});it('should support mount and update operations for multiple roots', () => {const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;const containerA = document.createElement('div');
const containerB = document.createElement('div');
act(() => {ReactDOM.render(<Parent key="A" count={3} />, containerA);
ReactDOM.render(<Parent key="B" count={2} />, containerB);
});expect(store).toMatchInlineSnapshot(`
[root]
▾ <Parent key="A">▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Child key="2"><div>[root]
▾ <Parent key="B">▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>`);act(() => {ReactDOM.render(<Parent key="A" count={4} />, containerA);
ReactDOM.render(<Parent key="B" count={1} />, containerB);
});expect(store).toMatchInlineSnapshot(`
[root]
▾ <Parent key="A">▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Child key="2"><div>▾ <Child key="3"><div>[root]
▾ <Parent key="B">▾ <div>▾ <Child key="0"><div>`);act(() => ReactDOM.unmountComponentAtNode(containerB));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Parent key="A">▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Child key="2"><div>▾ <Child key="3"><div>`);act(() => ReactDOM.unmountComponentAtNode(containerA));
expect(store).toMatchInlineSnapshot(``);
});it('should not filter DOM nodes from the store tree', () => {const Grandparent = ({flip}) => (<div><div><Parent flip={flip} /></div><Parent flip={flip} /><Nothing /></div>);const Parent = ({flip}) => (<div>{flip ? 'foo' : null}
<Child />{flip && [null, 'hello', 42]}
{flip ? 'bar' : 'baz'}
</div>);const Child = () => <div>Hi!</div>;const Nothing = () => null;const container = document.createElement('div');
act(() =>ReactDOM.render(<Grandparent count={4} flip={false} />, container),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <div>▾ <Parent>▾ <div>▾ <Child><div>▾ <Parent>▾ <div>▾ <Child><div><Nothing>`);act(() =>ReactDOM.render(<Grandparent count={4} flip={true} />, container),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <div>▾ <Parent>▾ <div>▾ <Child><div>▾ <Parent>▾ <div>▾ <Child><div><Nothing>`);act(() => ReactDOM.unmountComponentAtNode(container));
expect(store).toMatchInlineSnapshot(``);
});it('should support collapsing parts of the tree', () => {const Grandparent = ({count}) => (<div><Parent count={count} /><Parent count={count} /></div>);const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;act(() =>ReactDOM.render(
<Grandparent count={2} />,
document.createElement('div'),
),);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>`);const grandparentID = store.getElementIDAtIndex(0);
const parentOneID = store.getElementIDAtIndex(2);
const parentTwoID = store.getElementIDAtIndex(8);
act(() => store.toggleIsCollapsed(parentOneID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <Parent>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>`);act(() => store.toggleIsCollapsed(parentTwoID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <Parent>▸ <Parent>`);act(() => store.toggleIsCollapsed(parentOneID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▸ <Parent>`);act(() => store.toggleIsCollapsed(grandparentID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Grandparent>`);act(() => store.toggleIsCollapsed(grandparentID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▾ <div>▾ <Child key="0"><div>▾ <Child key="1"><div>▸ <Parent>`);});it('should support adding and removing children', () => {const Root = ({children}) => <div>{children}</div>;const Component = () => <div />;const container = document.createElement('div');
act(() =>ReactDOM.render(
<Root><Component key="a" /></Root>,container,),);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Component key="a"><div>`);act(() =>ReactDOM.render(
<Root><Component key="a" /><Component key="b" /></Root>,container,),);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Component key="a"><div>▾ <Component key="b"><div>`);act(() =>ReactDOM.render(
<Root><Component key="b" /></Root>,container,),);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Component key="b"><div>`);});it('should support reordering of children', () => {const Root = ({children}) => <div>{children}</div>;const Component = () => <div />;const Foo = () => <div>{[<Component key="0" />]}</div>;
const Bar = () => (<div>{[<Component key="0" />, <Component key="1" />]}</div>
);const foo = <Foo key="foo" />;const bar = <Bar key="bar" />;const container = document.createElement('div');
act(() => ReactDOM.render(<Root>{[foo, bar]}</Root>, container));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Foo key="foo">▾ <div>▾ <Component key="0"><div>▾ <Bar key="bar">▾ <div>▾ <Component key="0"><div>▾ <Component key="1"><div>`);act(() => ReactDOM.render(<Root>{[bar, foo]}</Root>, container));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Bar key="bar">▾ <div>▾ <Component key="0"><div>▾ <Component key="1"><div>▾ <Foo key="foo">▾ <div>▾ <Component key="0"><div>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), true));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Root>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Bar key="bar">▾ <div>▾ <Component key="0"><div>▾ <Component key="1"><div>▾ <Foo key="foo">▾ <div>▾ <Component key="0"><div>`);});});describe('collapseNodesByDefault:true', () => {beforeEach(() => {store.collapseNodesByDefault = true;
});it('should support mount and update operations', () => {const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;const container = document.createElement('div');
act(() =>ReactDOM.render(
<div><Parent count={1} />
<Parent count={3} />
</div>,container,),);expect(store).toMatchInlineSnapshot(`
[root]
▸ <div>`);act(() =>ReactDOM.render(
<div><Parent count={2} />
<Parent count={1} />
</div>,container,),);expect(store).toMatchInlineSnapshot(`
[root]
▸ <div>`);act(() => ReactDOM.unmountComponentAtNode(container));
expect(store).toMatchInlineSnapshot(``);
});it('should support mount and update operations for multiple roots', () => {const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;const containerA = document.createElement('div');
const containerB = document.createElement('div');
act(() => {ReactDOM.render(<Parent key="A" count={3} />, containerA);
ReactDOM.render(<Parent key="B" count={2} />, containerB);
});expect(store).toMatchInlineSnapshot(`
[root]
▸ <Parent key="A">[root]
▸ <Parent key="B">`);act(() => {ReactDOM.render(<Parent key="A" count={4} />, containerA);
ReactDOM.render(<Parent key="B" count={1} />, containerB);
});expect(store).toMatchInlineSnapshot(`
[root]
▸ <Parent key="A">[root]
▸ <Parent key="B">`);act(() => ReactDOM.unmountComponentAtNode(containerB));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Parent key="A">`);act(() => ReactDOM.unmountComponentAtNode(containerA));
expect(store).toMatchInlineSnapshot(``);
});it('should not filter DOM nodes from the store tree', () => {const Grandparent = ({flip}) => (<div><div><Parent flip={flip} /></div><Parent flip={flip} /><Nothing /></div>);const Parent = ({flip}) => (<div>{flip ? 'foo' : null}
<Child />{flip && [null, 'hello', 42]}
{flip ? 'bar' : 'baz'}
</div>);const Child = () => <div>Hi!</div>;const Nothing = () => null;const container = document.createElement('div');
act(() =>ReactDOM.render(<Grandparent count={4} flip={false} />, container),
);expect(store).toMatchInlineSnapshot(`
[root]
▸ <Grandparent>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▸ <div>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(1), false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <div>▸ <Parent><Nothing>`);act(() =>ReactDOM.render(<Grandparent count={4} flip={true} />, container),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <div>▸ <Parent><Nothing>`);act(() => ReactDOM.unmountComponentAtNode(container));
expect(store).toMatchInlineSnapshot(``);
});it('should support expanding parts of the tree', () => {const Grandparent = ({count}) => (<div><Parent count={count} /><Parent count={count} /></div>);const Parent = ({count}) => (<div>{new Array(count).fill(true).map((_, index) => (
<Child key={index} />))}</div>);const Child = () => <div>Hi!</div>;act(() =>ReactDOM.render(
<Grandparent count={2} />,
document.createElement('div'),
),);expect(store).toMatchInlineSnapshot(`
[root]
▸ <Grandparent>`);const grandparentID = store.getElementIDAtIndex(0);
act(() => store.toggleIsCollapsed(grandparentID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▸ <div>`);const parentDivID = store.getElementIDAtIndex(1);
act(() => store.toggleIsCollapsed(parentDivID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <Parent>▸ <Parent>`);const parentOneID = store.getElementIDAtIndex(2);
const parentTwoID = store.getElementIDAtIndex(3);
act(() => store.toggleIsCollapsed(parentOneID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▸ <div>▸ <Parent>`);act(() => store.toggleIsCollapsed(parentTwoID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▾ <Parent>▸ <div>▾ <Parent>▸ <div>`);act(() => store.toggleIsCollapsed(parentOneID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <Parent>▾ <Parent>▸ <div>`);act(() => store.toggleIsCollapsed(parentTwoID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <div>▸ <Parent>▸ <Parent>`);act(() => store.toggleIsCollapsed(grandparentID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Grandparent>`);});it('should support expanding deep parts of the tree', () => {const Wrapper = ({forwardedRef}) => (<Nested depth={3} forwardedRef={forwardedRef} />
);const Nested = ({depth, forwardedRef}) =>depth > 0 ? (
<Nested depth={depth - 1} forwardedRef={forwardedRef} />) : (<div ref={forwardedRef} />);let ref = null;const refSetter = value => {ref = value;};act(() =>ReactDOM.render(
<Wrapper forwardedRef={refSetter} />,document.createElement('div'),
),);expect(store).toMatchInlineSnapshot(`
[root]
▸ <Wrapper>`);const deepestedNodeID = global.agent.getIDForNode(ref);
act(() => store.toggleIsCollapsed(deepestedNodeID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Wrapper>▾ <Nested>▾ <Nested>▾ <Nested>▾ <Nested><div>`);const rootID = store.getElementIDAtIndex(0);
act(() => store.toggleIsCollapsed(rootID, true));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Wrapper>`);act(() => store.toggleIsCollapsed(rootID, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Wrapper>▾ <Nested>▾ <Nested>▾ <Nested>▾ <Nested><div>`);const id = store.getElementIDAtIndex(1);
act(() => store.toggleIsCollapsed(id, true));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Wrapper>▸ <Nested>`);act(() => store.toggleIsCollapsed(id, false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Wrapper>▾ <Nested>▾ <Nested>▾ <Nested>▾ <Nested><div>`);});it('should support reordering of children', () => {const Root = ({children}) => <div>{children}</div>;const Component = () => <div />;const Foo = () => <div>{[<Component key="0" />]}</div>;
const Bar = () => (<div>{[<Component key="0" />, <Component key="1" />]}</div>
);const foo = <Foo key="foo" />;const bar = <Bar key="bar" />;const container = document.createElement('div');
act(() => ReactDOM.render(<Root>{[foo, bar]}</Root>, container));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Root>`);act(() => ReactDOM.render(<Root>{[bar, foo]}</Root>, container));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Root>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▸ <div>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(1), false));
expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▸ <Bar key="bar">▸ <Foo key="foo">`);act(() => {store.toggleIsCollapsed(store.getElementIDAtIndex(3), false);
store.toggleIsCollapsed(store.getElementIDAtIndex(2), false);
});expect(store).toMatchInlineSnapshot(`
[root]
▾ <Root>▾ <div>▾ <Bar key="bar">▸ <div>▾ <Foo key="foo">▸ <div>`);act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), true));
expect(store).toMatchInlineSnapshot(`
[root]
▸ <Root>`);});});describe('StrictMode compliance', () => {it('should mark all elements as strict mode compliant', () => {const App = () => null;const container = document.createElement('div');
act(() => ReactDOM.render(<App />, container));
expect(store.getElementAtIndex(0).isStrictModeNonCompliant).toBe(false);
});});});