mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Added basic tests for InspectedElementContext
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
"<rootDir>/src/__tests__/setupTests"
|
||||
],
|
||||
"snapshotSerializers": [
|
||||
"<rootDir>/src/__tests__/inspectedElementSerializer",
|
||||
"<rootDir>/src/__tests__/storeSerializer"
|
||||
],
|
||||
"testMatch": [
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`InspectedElementContext should inspect the currently selected element: 1: mount 1`] = `
|
||||
[root]
|
||||
<Example>
|
||||
`;
|
||||
|
||||
exports[`InspectedElementContext should inspect the currently selected element: 2: Inspected element 2 1`] = `
|
||||
{
|
||||
"id": 2,
|
||||
"owners": null,
|
||||
"context": null,
|
||||
"hooks": [
|
||||
{
|
||||
"id": 0,
|
||||
"isStateEditable": true,
|
||||
"name": "State",
|
||||
"value": 1,
|
||||
"subHooks": []
|
||||
}
|
||||
],
|
||||
"props": {
|
||||
"foo": 1,
|
||||
"bar": "abc"
|
||||
},
|
||||
"state": null
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`InspectedElementContext should poll for updates for the currently selected element: 1: mount 1`] = `
|
||||
[root]
|
||||
<Example>
|
||||
`;
|
||||
|
||||
exports[`InspectedElementContext should poll for updates for the currently selected element: 2: initial render 1`] = `
|
||||
{
|
||||
"id": 2,
|
||||
"owners": null,
|
||||
"context": null,
|
||||
"hooks": null,
|
||||
"props": {
|
||||
"foo": 1,
|
||||
"bar": "abc"
|
||||
},
|
||||
"state": null
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`InspectedElementContext should poll for updates for the currently selected element: 2: updated state 1`] = `
|
||||
{
|
||||
"id": 2,
|
||||
"owners": null,
|
||||
"context": null,
|
||||
"hooks": null,
|
||||
"props": {
|
||||
"foo": 2,
|
||||
"bar": "def"
|
||||
},
|
||||
"state": null
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,162 @@
|
||||
// @flow
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type { Element } from 'src/devtools/views/Components/types';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('InspectedElementContext', () => {
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
let BridgeContext;
|
||||
let InspectedElementContext;
|
||||
let InspectedElementContextController;
|
||||
let StoreContext;
|
||||
let TreeContextController;
|
||||
|
||||
beforeEach(() => {
|
||||
utils = require('./utils');
|
||||
utils.beforeEachProfiling();
|
||||
|
||||
bridge = global.bridge;
|
||||
store = global.store;
|
||||
store.collapseNodesByDefault = false;
|
||||
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
TestRenderer = utils.requireTestRenderer();
|
||||
|
||||
BridgeContext = require('src/devtools/views/context').BridgeContext;
|
||||
InspectedElementContext = require('src/devtools/views/Components/InspectedElementContext')
|
||||
.InspectedElementContext;
|
||||
InspectedElementContextController = require('src/devtools/views/Components/InspectedElementContext')
|
||||
.InspectedElementContextController;
|
||||
StoreContext = require('src/devtools/views/context').StoreContext;
|
||||
TreeContextController = require('src/devtools/views/Components/TreeContext')
|
||||
.TreeContextController;
|
||||
});
|
||||
|
||||
const Contexts = ({
|
||||
children,
|
||||
defaultSelectedElementID = null,
|
||||
defaultSelectedElementIndex = null,
|
||||
}) => (
|
||||
<BridgeContext.Provider value={bridge}>
|
||||
<StoreContext.Provider value={store}>
|
||||
<TreeContextController
|
||||
defaultSelectedElementID={defaultSelectedElementID}
|
||||
defaultSelectedElementIndex={defaultSelectedElementIndex}
|
||||
>
|
||||
<InspectedElementContextController>
|
||||
{children}
|
||||
</InspectedElementContextController>
|
||||
</TreeContextController>
|
||||
</StoreContext.Provider>
|
||||
</BridgeContext.Provider>
|
||||
);
|
||||
|
||||
it('should inspect the currently selected element', async done => {
|
||||
const Example = () => {
|
||||
const [count] = React.useState(1);
|
||||
return count;
|
||||
};
|
||||
|
||||
const container = document.createElement('div');
|
||||
utils.act(() => ReactDOM.render(<Example foo={1} bar="abc" />, container));
|
||||
expect(store).toMatchSnapshot('1: mount');
|
||||
|
||||
const example = ((store.getElementAtIndex(0): any): Element);
|
||||
|
||||
let didFinish = false;
|
||||
|
||||
function Suspender({ target }) {
|
||||
const { read } = React.useContext(InspectedElementContext);
|
||||
const inspectedElement = read(target.id);
|
||||
expect(inspectedElement).toMatchSnapshot(
|
||||
`2: Inspected element ${target.id}`
|
||||
);
|
||||
didFinish = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
await utils.actAsync(
|
||||
() =>
|
||||
TestRenderer.create(
|
||||
<Contexts
|
||||
defaultSelectedElementID={example.id}
|
||||
defaultSelectedElementIndex={0}
|
||||
>
|
||||
<React.Suspense fallback={null}>
|
||||
<Suspender target={example} />
|
||||
</React.Suspense>
|
||||
</Contexts>
|
||||
),
|
||||
3
|
||||
);
|
||||
expect(didFinish).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should poll for updates for the currently selected element', async done => {
|
||||
const Example = () => null;
|
||||
|
||||
const container = document.createElement('div');
|
||||
utils.act(() => ReactDOM.render(<Example foo={1} bar="abc" />, container));
|
||||
expect(store).toMatchSnapshot('1: mount');
|
||||
|
||||
const example = ((store.getElementAtIndex(0): any): Element);
|
||||
|
||||
let inspectedElement = null;
|
||||
|
||||
function Suspender({ target }) {
|
||||
const { read } = React.useContext(InspectedElementContext);
|
||||
inspectedElement = read(target.id);
|
||||
return null;
|
||||
}
|
||||
|
||||
await utils.actAsync(
|
||||
() =>
|
||||
TestRenderer.create(
|
||||
<Contexts
|
||||
defaultSelectedElementID={example.id}
|
||||
defaultSelectedElementIndex={0}
|
||||
>
|
||||
<React.Suspense fallback={null}>
|
||||
<Suspender target={example} />
|
||||
</React.Suspense>
|
||||
</Contexts>
|
||||
),
|
||||
3
|
||||
);
|
||||
expect(inspectedElement).toMatchSnapshot('2: initial render');
|
||||
|
||||
await utils.actAsync(() =>
|
||||
ReactDOM.render(<Example foo={2} bar="def" />, container)
|
||||
);
|
||||
|
||||
inspectedElement = null;
|
||||
await utils.actAsync(
|
||||
() =>
|
||||
TestRenderer.create(
|
||||
<Contexts
|
||||
defaultSelectedElementID={example.id}
|
||||
defaultSelectedElementIndex={0}
|
||||
>
|
||||
<React.Suspense fallback={null}>
|
||||
<Suspender target={example} />
|
||||
</React.Suspense>
|
||||
</Contexts>
|
||||
),
|
||||
1
|
||||
);
|
||||
expect(inspectedElement).toMatchSnapshot('2: updated state');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
// test() is part of Jest's serializer API
|
||||
export function test(maybeInspectedElement) {
|
||||
return (
|
||||
maybeInspectedElement !== null &&
|
||||
typeof maybeInspectedElement === 'object' &&
|
||||
maybeInspectedElement.hasOwnProperty('canEditFunctionProps') &&
|
||||
maybeInspectedElement.hasOwnProperty('canEditHooks') &&
|
||||
maybeInspectedElement.hasOwnProperty('canToggleSuspense') &&
|
||||
maybeInspectedElement.hasOwnProperty('canViewSource')
|
||||
);
|
||||
}
|
||||
|
||||
// print() is part of Jest's serializer API
|
||||
export function print(inspectedElement, serialize, indent) {
|
||||
return JSON.stringify(
|
||||
{
|
||||
id: inspectedElement.id,
|
||||
owners: inspectedElement.owners,
|
||||
context: inspectedElement.context,
|
||||
hooks: inspectedElement.hooks,
|
||||
props: inspectedElement.props,
|
||||
state: inspectedElement.state,
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export async function actAsync(
|
||||
callback();
|
||||
|
||||
// Resolve pending suspense promises
|
||||
jest.runAllTimers();
|
||||
jest.runOnlyPendingTimers();
|
||||
});
|
||||
|
||||
// Run cascading microtasks and flush scheduled React work.
|
||||
@@ -35,7 +35,7 @@ export async function actAsync(
|
||||
while (--numTimesToFlush >= 0) {
|
||||
// $FlowFixMe Flow doens't know about "await act()" yet
|
||||
await TestUtils.act(async () => {
|
||||
jest.runAllTimers();
|
||||
jest.runOnlyPendingTimers();
|
||||
Scheduler.flushAll();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -358,7 +358,6 @@ export default class Agent extends EventEmitter {
|
||||
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
|
||||
} else {
|
||||
renderer.selectElement(id);
|
||||
this._bridge.send('selectElement');
|
||||
|
||||
// When user selects an element, stop trying to restore the selection,
|
||||
// and instead remember the current selection for the next reload.
|
||||
|
||||
@@ -594,10 +594,17 @@ type Props = {|
|
||||
|
||||
// Used for automated testing
|
||||
defaultOwnerID?: ?number,
|
||||
defaultSelectedElementID?: ?number,
|
||||
defaultSelectedElementIndex?: ?number,
|
||||
|};
|
||||
|
||||
// TODO Remove TreeContextController wrapper element once global ConsearchText.write API exists.
|
||||
function TreeContextController({ children, defaultOwnerID }: Props) {
|
||||
function TreeContextController({
|
||||
children,
|
||||
defaultOwnerID,
|
||||
defaultSelectedElementID,
|
||||
defaultSelectedElementIndex,
|
||||
}: Props) {
|
||||
const bridge = useContext(BridgeContext);
|
||||
const store = useContext(StoreContext);
|
||||
|
||||
@@ -652,8 +659,10 @@ function TreeContextController({ children, defaultOwnerID }: Props) {
|
||||
const [state, dispatch] = useReducer(reducer, {
|
||||
// Tree
|
||||
numElements: store.numElements,
|
||||
selectedElementIndex: null,
|
||||
selectedElementID: null,
|
||||
selectedElementID:
|
||||
defaultSelectedElementID == null ? null : defaultSelectedElementID,
|
||||
selectedElementIndex:
|
||||
defaultSelectedElementIndex == null ? null : defaultSelectedElementIndex,
|
||||
|
||||
// Search
|
||||
searchIndex: null,
|
||||
|
||||
Reference in New Issue
Block a user