mirror of
https://github.com/facebook/react.git
synced 2026-02-26 02:14:59 +00:00
## Overview Updates `eslint-plugin-jest` and enables the recommended rules with some turned off that are unhelpful. The main motivations is: a) we have a few duplicated tests, which this found an I deleted b) making sure we don't accidentally commit skipped tests
233 lines
7.3 KiB
JavaScript
233 lines
7.3 KiB
JavaScript
/**
|
|
* 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 type Store from 'react-devtools-shared/src/devtools/store';
|
|
|
|
import {getVersionedRenderImplementation} from './utils';
|
|
|
|
describe('ProfilerStore', () => {
|
|
let React;
|
|
let store: Store;
|
|
let utils;
|
|
|
|
beforeEach(() => {
|
|
global.IS_REACT_ACT_ENVIRONMENT = true;
|
|
|
|
utils = require('./utils');
|
|
utils.beforeEachProfiling();
|
|
|
|
store = global.store;
|
|
store.collapseNodesByDefault = false;
|
|
store.recordChangeDescriptions = true;
|
|
|
|
React = require('react');
|
|
});
|
|
|
|
const {render, unmount} = getVersionedRenderImplementation();
|
|
const {render: renderOther, unmount: unmountOther} =
|
|
getVersionedRenderImplementation();
|
|
|
|
// @reactVersion >= 16.9
|
|
it('should not remove profiling data when roots are unmounted', async () => {
|
|
const Parent = ({count}) =>
|
|
new Array(count)
|
|
.fill(true)
|
|
.map((_, index) => <Child key={index} duration={index} />);
|
|
const Child = () => <div>Hi!</div>;
|
|
|
|
utils.act(() => {
|
|
render(<Parent key="A" count={3} />);
|
|
renderOther(<Parent key="B" count={2} />);
|
|
});
|
|
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
|
|
utils.act(() => {
|
|
render(<Parent key="A" count={4} />);
|
|
renderOther(<Parent key="B" count={1} />);
|
|
});
|
|
|
|
utils.act(() => store.profilerStore.stopProfiling());
|
|
|
|
const rootA = store.roots[0];
|
|
const rootB = store.roots[1];
|
|
|
|
utils.act(() => unmountOther());
|
|
expect(store.profilerStore.getDataForRoot(rootA)).not.toBeNull();
|
|
|
|
utils.act(() => unmount());
|
|
expect(store.profilerStore.getDataForRoot(rootB)).not.toBeNull();
|
|
});
|
|
|
|
// @reactVersion >= 16.9
|
|
it('should not allow new/saved profiling data to be set while profiling is in progress', () => {
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
const fauxProfilingData = {
|
|
dataForRoots: new Map(),
|
|
};
|
|
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
store.profilerStore.profilingData = fauxProfilingData;
|
|
expect(store.profilerStore.profilingData).not.toBe(fauxProfilingData);
|
|
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
expect(console.warn).toHaveBeenCalledWith(
|
|
'Profiling data cannot be updated while profiling is in progress.',
|
|
);
|
|
utils.act(() => store.profilerStore.stopProfiling());
|
|
store.profilerStore.profilingData = fauxProfilingData;
|
|
expect(store.profilerStore.profilingData).toBe(fauxProfilingData);
|
|
});
|
|
|
|
// @reactVersion >= 16.9
|
|
// This test covers current broken behavior (arguably) with the synthetic event system.
|
|
it('should filter empty commits', () => {
|
|
const inputRef = React.createRef();
|
|
const ControlledInput = () => {
|
|
const [name, setName] = React.useState('foo');
|
|
const handleChange = event => setName(event.target.value);
|
|
return <input ref={inputRef} value={name} onChange={handleChange} />;
|
|
};
|
|
|
|
// It's important that this test uses legacy sync mode.
|
|
// The root API does not trigger this particular failing case.
|
|
utils.act(() => render(<ControlledInput />));
|
|
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
|
|
// Sets a value in a way that React doesn't see,
|
|
// so that a subsequent "change" event will trigger the event handler.
|
|
const setUntrackedValue = Object.getOwnPropertyDescriptor(
|
|
HTMLInputElement.prototype,
|
|
'value',
|
|
).set;
|
|
|
|
const target = inputRef.current;
|
|
setUntrackedValue.call(target, 'bar');
|
|
target.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
|
|
expect(target.value).toBe('bar');
|
|
|
|
utils.act(() => store.profilerStore.stopProfiling());
|
|
|
|
// Only one commit should have been recorded (in response to the "change" event).
|
|
const root = store.roots[0];
|
|
const data = store.profilerStore.getDataForRoot(root);
|
|
expect(data.commitData).toHaveLength(1);
|
|
expect(data.operations).toHaveLength(1);
|
|
});
|
|
|
|
// @reactVersion >= 16.9
|
|
it('should filter empty commits alt', () => {
|
|
let commitCount = 0;
|
|
|
|
const inputRef = React.createRef();
|
|
const Example = () => {
|
|
const [, setTouched] = React.useState(false);
|
|
|
|
const handleBlur = () => {
|
|
setTouched(true);
|
|
};
|
|
|
|
require('scheduler').unstable_advanceTime(1);
|
|
|
|
React.useLayoutEffect(() => {
|
|
commitCount++;
|
|
});
|
|
|
|
return <input ref={inputRef} onBlur={handleBlur} />;
|
|
};
|
|
|
|
// It's important that this test uses legacy sync mode.
|
|
// The root API does not trigger this particular failing case.
|
|
utils.act(() => render(<Example />));
|
|
|
|
expect(commitCount).toBe(1);
|
|
commitCount = 0;
|
|
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
|
|
// Focus and blur.
|
|
const target = inputRef.current;
|
|
utils.act(() => target.focus());
|
|
utils.act(() => target.blur());
|
|
utils.act(() => target.focus());
|
|
utils.act(() => target.blur());
|
|
expect(commitCount).toBe(1);
|
|
|
|
utils.act(() => store.profilerStore.stopProfiling());
|
|
|
|
// Only one commit should have been recorded (in response to the "change" event).
|
|
const root = store.roots[0];
|
|
const data = store.profilerStore.getDataForRoot(root);
|
|
expect(data.commitData).toHaveLength(1);
|
|
expect(data.operations).toHaveLength(1);
|
|
});
|
|
|
|
// @reactVersion >= 16.9
|
|
it('should throw if component filters are modified while profiling', () => {
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
|
|
expect(() => {
|
|
utils.act(() => {
|
|
const {
|
|
ElementTypeHostComponent,
|
|
} = require('react-devtools-shared/src/frontend/types');
|
|
store.componentFilters = [
|
|
utils.createElementTypeFilter(ElementTypeHostComponent),
|
|
];
|
|
});
|
|
}).toThrow('Cannot modify filter preferences while profiling');
|
|
});
|
|
|
|
// @reactVersion >= 16.9
|
|
it('should not throw if state contains a property hasOwnProperty', () => {
|
|
let setStateCallback;
|
|
const ControlledInput = () => {
|
|
const [state, setState] = React.useState({hasOwnProperty: true});
|
|
setStateCallback = setState;
|
|
return state.hasOwnProperty;
|
|
};
|
|
|
|
// It's important that this test uses legacy sync mode.
|
|
// The root API does not trigger this particular failing case.
|
|
utils.act(() => render(<ControlledInput />));
|
|
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
utils.act(() =>
|
|
setStateCallback({
|
|
hasOwnProperty: false,
|
|
}),
|
|
);
|
|
utils.act(() => store.profilerStore.stopProfiling());
|
|
|
|
// Only one commit should have been recorded (in response to the "change" event).
|
|
const root = store.roots[0];
|
|
const data = store.profilerStore.getDataForRoot(root);
|
|
expect(data.commitData).toHaveLength(1);
|
|
expect(data.operations).toHaveLength(1);
|
|
});
|
|
|
|
// @reactVersion >= 18.0
|
|
it('should not throw while initializing context values for Fibers within a not-yet-mounted subtree', () => {
|
|
const promise = new Promise(resolve => {});
|
|
const SuspendingView = () => {
|
|
throw promise;
|
|
};
|
|
|
|
const App = () => {
|
|
return (
|
|
<React.Suspense fallback="Fallback">
|
|
<SuspendingView />
|
|
</React.Suspense>
|
|
);
|
|
};
|
|
|
|
utils.act(() => render(<App />));
|
|
utils.act(() => store.profilerStore.startProfiling());
|
|
});
|
|
});
|