Skip to content

Commit 8201a8f

Browse files
committed
[devtools] Fix can't expand prop value in some scenarios
1 parent 50393dc commit 8201a8f

File tree

5 files changed

+172
-4
lines changed

5 files changed

+172
-4
lines changed

packages/react-devtools-shared/src/__tests__/__snapshots__/inspectedElementContext-test.js.snap

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`InspectedElementContext should allow component prop value and value\`s prototype has same name params.: 1: Inspected element 2 1`] = `
4+
{
5+
"id": 2,
6+
"owners": null,
7+
"context": null,
8+
"hooks": null,
9+
"props": {
10+
"data": {
11+
"b": null,
12+
"c": null,
13+
"d": "normal"
14+
}
15+
},
16+
"state": null
17+
}
18+
`;
19+
320
exports[`InspectedElementContext should dehydrate complex nested values when requested: 1: Initially inspect element 1`] = `
421
{
522
"id": 2,

packages/react-devtools-shared/src/__tests__/inspectedElementContext-test.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,82 @@ describe('InspectedElementContext', () => {
11071107
done();
11081108
});
11091109

1110+
it('should allow component prop value and value`s prototype has same name params.', async done => {
1111+
const testData = Object.create(
1112+
{
1113+
a: undefined,
1114+
b: Infinity,
1115+
c: NaN,
1116+
d: 'normal',
1117+
},
1118+
{
1119+
a: {
1120+
value: undefined,
1121+
writable: true,
1122+
enumerable: true,
1123+
configurable: true,
1124+
},
1125+
b: {
1126+
value: Infinity,
1127+
writable: true,
1128+
enumerable: true,
1129+
configurable: true,
1130+
},
1131+
c: {
1132+
value: NaN,
1133+
writable: true,
1134+
enumerable: true,
1135+
configurable: true,
1136+
},
1137+
d: {
1138+
value: 'normal',
1139+
writable: true,
1140+
enumerable: true,
1141+
configurable: true,
1142+
},
1143+
},
1144+
);
1145+
const Example = ({data}) => null;
1146+
const container = document.createElement('div');
1147+
await utils.actAsync(() =>
1148+
ReactDOM.render(<Example data={testData} />, container),
1149+
);
1150+
1151+
const id = ((store.getElementIDAtIndex(0): any): number);
1152+
1153+
let inspectedElement = null;
1154+
1155+
function Suspender({target}) {
1156+
const {getInspectedElement} = React.useContext(InspectedElementContext);
1157+
inspectedElement = getInspectedElement(id);
1158+
return null;
1159+
}
1160+
1161+
await utils.actAsync(
1162+
() =>
1163+
TestRenderer.create(
1164+
<Contexts
1165+
defaultSelectedElementID={id}
1166+
defaultSelectedElementIndex={0}>
1167+
<React.Suspense fallback={null}>
1168+
<Suspender target={id} />
1169+
</React.Suspense>
1170+
</Contexts>,
1171+
),
1172+
false,
1173+
);
1174+
expect(inspectedElement).not.toBeNull();
1175+
expect(inspectedElement).toMatchSnapshot(`1: Inspected element ${id}`);
1176+
expect(inspectedElement.props.data).toEqual({
1177+
a: undefined,
1178+
b: Infinity,
1179+
c: NaN,
1180+
d: 'normal',
1181+
});
1182+
1183+
done();
1184+
});
1185+
11101186
it('should not dehydrate nested values until explicitly requested', async done => {
11111187
const Example = () => {
11121188
const [state] = React.useState({

packages/react-devtools-shared/src/__tests__/legacy/__snapshots__/inspectElement-test.js.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`InspectedElementContext should allow component prop value and value\`s prototype has same name params.: 1: Initially inspect element 1`] = `
4+
Object {
5+
"id": 2,
6+
"type": "full-data",
7+
"value": {
8+
"id": 2,
9+
"owners": null,
10+
"context": {},
11+
"hooks": null,
12+
"props": {
13+
"data": {
14+
"b": null,
15+
"c": null,
16+
"d": "normal"
17+
}
18+
},
19+
"state": null
20+
},
21+
}
22+
`;
23+
324
exports[`InspectedElementContext should inspect the currently selected element: 1: Initial inspection 1`] = `
425
Object {
526
"id": 2,

packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {InspectedElementPayload} from 'react-devtools-shared/src/backend/ty
1111
import type {DehydratedData} from 'react-devtools-shared/src/devtools/views/Components/types';
1212
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
1313
import type Store from 'react-devtools-shared/src/devtools/store';
14+
import {element} from 'prop-types';
1415

1516
describe('InspectedElementContext', () => {
1617
let React;
@@ -537,6 +538,59 @@ describe('InspectedElementContext', () => {
537538
done();
538539
});
539540

541+
it('should allow component prop value and value`s prototype has same name params.', async done => {
542+
const testData = Object.create(
543+
{
544+
a: undefined,
545+
b: Infinity,
546+
c: NaN,
547+
d: 'normal',
548+
},
549+
{
550+
a: {
551+
value: undefined,
552+
writable: true,
553+
enumerable: true,
554+
configurable: true,
555+
},
556+
b: {
557+
value: Infinity,
558+
writable: true,
559+
enumerable: true,
560+
configurable: true,
561+
},
562+
c: {
563+
value: NaN,
564+
writable: true,
565+
enumerable: true,
566+
configurable: true,
567+
},
568+
d: {
569+
value: 'normal',
570+
writable: true,
571+
enumerable: true,
572+
configurable: true,
573+
},
574+
},
575+
);
576+
const Example = ({data}) => null;
577+
act(() =>
578+
ReactDOM.render(
579+
<Example data={testData} />,
580+
document.createElement('div'),
581+
),
582+
);
583+
const id = ((store.getElementIDAtIndex(0): any): number);
584+
let inspectedElement = await read(id);
585+
expect(inspectedElement).toMatchSnapshot('1: Initially inspect element');
586+
const {props} = inspectedElement.value;
587+
expect(props.data.a).toBeUndefined();
588+
expect(Number.isFinite(props.data.b)).toBe(false);
589+
expect(props.data.c).toBeNaN();
590+
591+
done();
592+
});
593+
540594
it('should not dehydrate nested values until explicitly requested', async done => {
541595
const Example = () => null;
542596

packages/react-devtools-shared/src/utils.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ export function alphaSortKeys(
7070

7171
export function getAllEnumerableKeys(
7272
obj: Object,
73-
): Array<string | number | Symbol> {
74-
const keys = [];
73+
): Set<string | number | Symbol> {
74+
const keys = new Set();
7575
let current = obj;
7676
while (current != null) {
7777
const currentKeys = [
@@ -82,7 +82,7 @@ export function getAllEnumerableKeys(
8282
currentKeys.forEach(key => {
8383
// $FlowFixMe: key can be a Symbol https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
8484
if (descriptors[key].enumerable) {
85-
keys.push(key);
85+
keys.add(key);
8686
}
8787
});
8888
current = Object.getPrototypeOf(current);
@@ -767,7 +767,7 @@ export function formatDataForPreview(
767767
return data.toString();
768768
case 'object':
769769
if (showFormattedValue) {
770-
const keys = getAllEnumerableKeys(data).sort(alphaSortKeys);
770+
const keys = Array.from(getAllEnumerableKeys(data)).sort(alphaSortKeys);
771771
772772
let formatted = '';
773773
for (let i = 0; i < keys.length; i++) {

0 commit comments

Comments
 (0)