/*** 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*/import typeof ReactTestRenderer from 'react-test-renderer';
import type {Element} from 'react-devtools-shared/src/frontend/types';
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type Store from 'react-devtools-shared/src/devtools/store';
describe('OwnersListContext', () => {
let React;
let TestRenderer: ReactTestRenderer;
let bridge: FrontendBridge;
let legacyRender;
let store: Store;
let utils;
let BridgeContext;
let OwnersListContext;
let OwnersListContextController;
let StoreContext;
let TreeContextController;
beforeEach(() => {
utils = require('./utils');
utils.beforeEachProfiling();
legacyRender = utils.legacyRender;
bridge = global.bridge;
store = global.store;
store.collapseNodesByDefault = false;
React = require('react');
TestRenderer = utils.requireTestRenderer();
BridgeContext =
require('react-devtools-shared/src/devtools/views/context').BridgeContext;
OwnersListContext =
require('react-devtools-shared/src/devtools/views/Components/OwnersListContext').OwnersListContext;
OwnersListContextController =
require('react-devtools-shared/src/devtools/views/Components/OwnersListContext').OwnersListContextController;
StoreContext =
require('react-devtools-shared/src/devtools/views/context').StoreContext;
TreeContextController =
require('react-devtools-shared/src/devtools/views/Components/TreeContext').TreeContextController;
});const Contexts = ({children, defaultOwnerID = null}) => (
<BridgeContext.Provider value={bridge}>
<StoreContext.Provider value={store}>
<TreeContextController defaultOwnerID={defaultOwnerID}>
<OwnersListContextController>{children}</OwnersListContextController>
</TreeContextController>
</StoreContext.Provider>
</BridgeContext.Provider>
);
async function getOwnersListForOwner(owner) {
let ownerDisplayNames = null;
function Suspender() {
const read = React.useContext(OwnersListContext);
const owners = read(owner.id);
ownerDisplayNames = owners.map(({displayName}) => displayName);
return null;
}await utils.actAsync(() =>
TestRenderer.create(
<Contexts defaultOwnerID={owner.id}>
<React.Suspense fallback={null}>
<Suspender owner={owner} />
</React.Suspense>
</Contexts>,
),);expect(ownerDisplayNames).not.toBeNull();
return ownerDisplayNames;
}it('should fetch the owners list for the selected element', async () => {
const Grandparent = () => <Parent />;
const Parent = () => {
return (
<React.Fragment>
<Child />
<Child />
</React.Fragment>
);};const Child = () => null;utils.act(() =>
legacyRender(<Grandparent />, document.createElement('div')),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <Parent><Child><Child>`);const parent = ((store.getElementAtIndex(1): any): Element);
const firstChild = ((store.getElementAtIndex(2): any): Element);
expect(await getOwnersListForOwner(parent)).toMatchInlineSnapshot(`
[
"Grandparent","Parent",]`);expect(await getOwnersListForOwner(firstChild)).toMatchInlineSnapshot(`
[
"Grandparent","Parent","Child",]`);});it('should fetch the owners list for the selected element that includes filtered components', async () => {store.componentFilters = [utils.createDisplayNameFilter('^Parent$')];
const Grandparent = () => <Parent />;const Parent = () => {return (<React.Fragment>
<Child /><Child /></React.Fragment>
);};const Child = () => null;utils.act(() =>
legacyRender(<Grandparent />, document.createElement('div')),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent><Child><Child>`);const firstChild = ((store.getElementAtIndex(1): any): Element);
expect(await getOwnersListForOwner(firstChild)).toMatchInlineSnapshot(`
[
"Grandparent","Parent","Child",]`);});it('should include the current element even if there are no other owners', async () => {store.componentFilters = [utils.createDisplayNameFilter('^Parent$')];
const Grandparent = () => <Parent />;const Parent = () => null;utils.act(() =>
legacyRender(<Grandparent />, document.createElement('div')),
);expect(store).toMatchInlineSnapshot(`
[root]
<Grandparent>`);const grandparent = ((store.getElementAtIndex(0): any): Element);
expect(await getOwnersListForOwner(grandparent)).toMatchInlineSnapshot(`
[
"Grandparent",]`);});it('should include all owners for a component wrapped in react memo', async () => {const InnerComponent = (props, ref) => <div ref={ref} />;const ForwardRef = React.forwardRef(InnerComponent);
const Memo = React.memo(ForwardRef);
const Grandparent = () => {const ref = React.createRef();
return <Memo ref={ref} />;};utils.act(() =>
legacyRender(<Grandparent />, document.createElement('div')),
);expect(store).toMatchInlineSnapshot(`
[root]
▾ <Grandparent>▾ <InnerComponent> [Memo]
<InnerComponent> [ForwardRef]
`);const wrapped = ((store.getElementAtIndex(2): any): Element);
expect(await getOwnersListForOwner(wrapped)).toMatchInlineSnapshot(`
[
"Grandparent","InnerComponent","InnerComponent",]`);});});