@samitouri / QOS-React-2 / commits / 195b3db618

Added missing guard to DevTools for Objects with null proto (#17757)

This prevents a runtime error from occurring when these objects are inspected.

Brian Vaughn committed Jan 2, 2020 at 08:27 UTC 195b3db61885552b84eacb2ab51502b342d0fa8a
6 files changed +44 -6
packages/react-devtools-shared/src/__tests__/__snapshots__/inspectedElementContext-test.js.snap
+5
@@ -510,6 +510,11 @@ exports[`InspectedElementContext should support complex data types: 1: Inspected
510 "object_of_objects": {
511 "inner": {}
512 },
513 + "object_with_null_proto": {
514 + "string": "abc",
515 + "number": 123,
516 + "boolean": true
517 + },
518 "react_element": {},
519 "regexp": {},
520 "set": {
packages/react-devtools-shared/src/__tests__/inspectedElementContext-test.js
+14 -2
@@ -524,7 +524,7 @@ describe('InspectedElementContext', () => {
524 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
525 const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
526 const objectOfObjects = {
527 - inner: {string: 'abc', number: 213, boolean: true},
527 + inner: {string: 'abc', number: 123, boolean: true},
528 };
529 const typedArray = Int8Array.from([100, -100, 0]);
530 const arrayBuffer = typedArray.buffer;
@@ -537,6 +537,10 @@ describe('InspectedElementContext', () => {
537 xyz: 1,
538 },
539 });
540 + const objectWithNullProto = Object.create(null);
541 + objectWithNullProto.string = 'abc';
542 + objectWithNullProto.number = 123;
543 + objectWithNullProto.boolean = true;
544
545 const container = document.createElement('div');
546 await utils.actAsync(() =>
@@ -554,6 +558,7 @@ describe('InspectedElementContext', () => {
558 map={mapShallow}
559 map_of_maps={mapOfMaps}
560 object_of_objects={objectOfObjects}
561 + object_with_null_proto={objectWithNullProto}
562 react_element={<span />}
563 regexp={/abc/giu}
564 set={setShallow}
@@ -604,6 +609,7 @@ describe('InspectedElementContext', () => {
609 map,
610 map_of_maps,
611 object_of_objects,
612 + object_with_null_proto,
613 react_element,
614 regexp,
615 set,
@@ -691,10 +697,16 @@ describe('InspectedElementContext', () => {
697 expect(object_of_objects.inner[meta.name]).toBe('');
698 expect(object_of_objects.inner[meta.type]).toBe('object');
699 expect(object_of_objects.inner[meta.preview_long]).toBe(
694 - '{boolean: true, number: 213, string: "abc"}',
700 + '{boolean: true, number: 123, string: "abc"}',
701 );
702 expect(object_of_objects.inner[meta.preview_short]).toBe('{…}');
703
704 + expect(object_with_null_proto).toEqual({
705 + boolean: true,
706 + number: 123,
707 + string: 'abc',
708 + });
709 +
710 expect(react_element[meta.inspectable]).toBe(false);
711 expect(react_element[meta.name]).toBe('span');
712 expect(react_element[meta.type]).toBe('react_element');
packages/react-devtools-shared/src/__tests__/legacy/__snapshots__/inspectElement-test.js.snap
+5
@@ -151,6 +151,11 @@ Object {
151 "object_of_objects": {
152 "inner": {}
153 },
154 + "object_with_null_proto": {
155 + "string": "abc",
156 + "number": 123,
157 + "boolean": true
158 + },
159 "react_element": {},
160 "regexp": {},
161 "set": {
packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js
+14 -2
@@ -155,7 +155,7 @@ describe('InspectedElementContext', () => {
155 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
156 const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
157 const objectOfObjects = {
158 - inner: {string: 'abc', number: 213, boolean: true},
158 + inner: {string: 'abc', number: 123, boolean: true},
159 };
160 const typedArray = Int8Array.from([100, -100, 0]);
161 const arrayBuffer = typedArray.buffer;
@@ -168,6 +168,10 @@ describe('InspectedElementContext', () => {
168 xyz: 1,
169 },
170 });
171 + const objectWithNullProto = Object.create(null);
172 + objectWithNullProto.string = 'abc';
173 + objectWithNullProto.number = 123;
174 + objectWithNullProto.boolean = true;
175
176 act(() =>
177 ReactDOM.render(
@@ -184,6 +188,7 @@ describe('InspectedElementContext', () => {
188 map={mapShallow}
189 map_of_maps={mapOfMaps}
190 object_of_objects={objectOfObjects}
191 + object_with_null_proto={objectWithNullProto}
192 react_element={<span />}
193 regexp={/abc/giu}
194 set={setShallow}
@@ -212,6 +217,7 @@ describe('InspectedElementContext', () => {
217 map,
218 map_of_maps,
219 object_of_objects,
220 + object_with_null_proto,
221 react_element,
222 regexp,
223 set,
@@ -273,10 +279,16 @@ describe('InspectedElementContext', () => {
279 expect(object_of_objects.inner[meta.name]).toBe('');
280 expect(object_of_objects.inner[meta.type]).toBe('object');
281 expect(object_of_objects.inner[meta.preview_long]).toBe(
276 - '{boolean: true, number: 213, string: "abc"}',
282 + '{boolean: true, number: 123, string: "abc"}',
283 );
284 expect(object_of_objects.inner[meta.preview_short]).toBe('{…}');
285
286 + expect(object_with_null_proto).toEqual({
287 + boolean: true,
288 + number: 123,
289 + string: 'abc',
290 + });
291 +
292 expect(react_element[meta.inspectable]).toBe(false);
293 expect(react_element[meta.name]).toBe('span');
294 expect(react_element[meta.type]).toBe('react_element');
packages/react-devtools-shared/src/utils.js
+2 -2
@@ -388,7 +388,7 @@ export function getDataType(data: Object): DataType {
388 return data.constructor.hasOwnProperty('BYTES_PER_ELEMENT')
389 ? 'typed_array'
390 : 'data_view';
391 - } else if (data.constructor.name === 'ArrayBuffer') {
391 + } else if (data.constructor && data.constructor.name === 'ArrayBuffer') {
392 // HACK This ArrayBuffer check is gross; is there a better way?
393 // We could try to create a new DataView with the value.
394 // If it doesn't error, we know it's an ArrayBuffer,
@@ -396,7 +396,7 @@ export function getDataType(data: Object): DataType {
396 return 'array_buffer';
397 } else if (typeof data[Symbol.iterator] === 'function') {
398 return 'iterator';
399 - } else if (data.constructor.name === 'RegExp') {
399 + } else if (data.constructor && data.constructor.name === 'RegExp') {
400 return 'regexp';
401 } else if (Object.prototype.toString.call(data) === '[object Date]') {
402 return 'date';
packages/react-devtools-shell/src/app/InspectableElements/UnserializableProps.js
+4
@@ -25,6 +25,9 @@ const immutable = Immutable.fromJS({
25 xyz: 1,
26 },
27 });
28 +const objectWithNullProto = Object.create(null);
29 +objectWithNullProto.foo = 'abc';
30 +objectWithNullProto.bar = 123;
31
32 export default function UnserializableProps() {
33 return (
@@ -37,6 +40,7 @@ export default function UnserializableProps() {
40 setOfSets={setOfSets}
41 typedArray={typedArray}
42 immutable={immutable}
43 + objectWithNullProto={objectWithNullProto}
44 />
45 );
46 }