diff --git a/packages/react-devtools-shared/src/__tests__/dehydratedValueSerializer.js b/packages/react-devtools-shared/src/__tests__/dehydratedValueSerializer.js index d8eac57df035c..23a9a1af02ef2 100644 --- a/packages/react-devtools-shared/src/__tests__/dehydratedValueSerializer.js +++ b/packages/react-devtools-shared/src/__tests__/dehydratedValueSerializer.js @@ -10,10 +10,14 @@ // test() is part of Jest's serializer API export function test(maybeDehydratedValue) { const {meta} = require('react-devtools-shared/src/hydration'); + + const hasOwnProperty = Object.prototype.hasOwnProperty.bind( + maybeDehydratedValue, + ); return ( maybeDehydratedValue !== null && typeof maybeDehydratedValue === 'object' && - maybeDehydratedValue.hasOwnProperty(meta.inspectable) && + hasOwnProperty(meta.inspectable) && maybeDehydratedValue[meta.inspected] !== true ); } diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index 60119df3a972b..1acc8a67c5db0 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -20,7 +20,6 @@ describe('InspectedElement', () => { let TestRenderer: ReactTestRenderer; let bridge: FrontendBridge; let store: Store; - let meta; let utils; let BridgeContext; @@ -39,8 +38,6 @@ describe('InspectedElement', () => { utils = require('./utils'); utils.beforeEachProfiling(); - meta = require('react-devtools-shared/src/hydration').meta; - bridge = global.bridge; store = global.store; store.collapseNodesByDefault = false; @@ -442,18 +439,21 @@ describe('InspectedElement', () => { const inspectedElement = await inspectElementAtIndex(0); - const {props} = (inspectedElement: any); - expect(props.boolean_false).toBe(false); - expect(props.boolean_true).toBe(true); - expect(Number.isFinite(props.infinity)).toBe(false); - expect(props.integer_zero).toEqual(0); - expect(props.integer_one).toEqual(1); - expect(props.float).toEqual(1.23); - expect(props.string).toEqual('abc'); - expect(props.string_empty).toEqual(''); - expect(props.nan).toBeNaN(); - expect(props.value_null).toBeNull(); - expect(props.value_undefined).toBeUndefined(); + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "boolean_false": false, + "boolean_true": true, + "float": 1.23, + "infinity": Infinity, + "integer_one": 1, + "integer_zero": 0, + "nan": NaN, + "string": "abc", + "string_empty": "", + "value_null": null, + "value_undefined": undefined, + } + `); }); it('should support complex data types', async () => { @@ -539,175 +539,126 @@ describe('InspectedElement', () => { const inspectedElement = await inspectElementAtIndex(0); - const { - anonymous_fn, - array_buffer, - array_of_arrays, - big_int, - bound_fn, - data_view, - date, - fn, - html_element, - immutable, - map, - map_of_maps, - object_of_objects, - object_with_symbol, - proxy, - react_element, - regexp, - set, - set_of_sets, - symbol, - typed_array, - } = (inspectedElement: any).props; - - expect(anonymous_fn[meta.inspectable]).toBe(false); - expect(anonymous_fn[meta.name]).toBe('function'); - expect(anonymous_fn[meta.type]).toBe('function'); - expect(anonymous_fn[meta.preview_long]).toBe('ƒ () {}'); - expect(anonymous_fn[meta.preview_short]).toBe('ƒ () {}'); - - expect(array_buffer[meta.size]).toBe(3); - expect(array_buffer[meta.inspectable]).toBe(false); - expect(array_buffer[meta.name]).toBe('ArrayBuffer'); - expect(array_buffer[meta.type]).toBe('array_buffer'); - expect(array_buffer[meta.preview_short]).toBe('ArrayBuffer(3)'); - expect(array_buffer[meta.preview_long]).toBe('ArrayBuffer(3)'); - - expect(array_of_arrays[0][meta.size]).toBe(2); - expect(array_of_arrays[0][meta.inspectable]).toBe(true); - expect(array_of_arrays[0][meta.name]).toBe('Array'); - expect(array_of_arrays[0][meta.type]).toBe('array'); - expect(array_of_arrays[0][meta.preview_long]).toBe('[Array(3), Array(0)]'); - expect(array_of_arrays[0][meta.preview_short]).toBe('Array(2)'); - - expect(big_int[meta.inspectable]).toBe(false); - expect(big_int[meta.name]).toBe('123'); - expect(big_int[meta.type]).toBe('bigint'); - expect(big_int[meta.preview_long]).toBe('123n'); - expect(big_int[meta.preview_short]).toBe('123n'); - - expect(bound_fn[meta.inspectable]).toBe(false); - expect(bound_fn[meta.name]).toBe('bound exampleFunction'); - expect(bound_fn[meta.type]).toBe('function'); - expect(bound_fn[meta.preview_long]).toBe('ƒ bound exampleFunction() {}'); - expect(bound_fn[meta.preview_short]).toBe('ƒ bound exampleFunction() {}'); - - expect(data_view[meta.size]).toBe(3); - expect(data_view[meta.inspectable]).toBe(false); - expect(data_view[meta.name]).toBe('DataView'); - expect(data_view[meta.type]).toBe('data_view'); - expect(data_view[meta.preview_long]).toBe('DataView(3)'); - expect(data_view[meta.preview_short]).toBe('DataView(3)'); - - expect(date[meta.inspectable]).toBe(false); - expect(date[meta.type]).toBe('date'); - expect(new Date(date[meta.preview_long]).toISOString()).toBe( - exampleDateISO, - ); - expect(new Date(date[meta.preview_short]).toISOString()).toBe( - exampleDateISO, - ); - - expect(fn[meta.inspectable]).toBe(false); - expect(fn[meta.name]).toBe('exampleFunction'); - expect(fn[meta.type]).toBe('function'); - expect(fn[meta.preview_long]).toBe('ƒ exampleFunction() {}'); - expect(fn[meta.preview_short]).toBe('ƒ exampleFunction() {}'); - - expect(html_element[meta.inspectable]).toBe(false); - expect(html_element[meta.name]).toBe('DIV'); - expect(html_element[meta.type]).toBe('html_element'); - expect(html_element[meta.preview_long]).toBe('
'); - expect(html_element[meta.preview_short]).toBe(''); - - expect(immutable[meta.inspectable]).toBeUndefined(); // Complex type - expect(immutable[meta.name]).toBe('Map'); - expect(immutable[meta.type]).toBe('iterator'); - expect(immutable[meta.preview_long]).toBe( - 'Map(3) {"a" => List(3), "b" => 123, "c" => Map(2)}', - ); - expect(immutable[meta.preview_short]).toBe('Map(3)'); - - expect(map[meta.inspectable]).toBeUndefined(); // Complex type - expect(map[meta.name]).toBe('Map'); - expect(map[meta.type]).toBe('iterator'); - expect(map[0][meta.type]).toBe('array'); - expect(map[meta.preview_long]).toBe( - 'Map(2) {"name" => "Brian", "food" => "sushi"}', - ); - expect(map[meta.preview_short]).toBe('Map(2)'); - - expect(map_of_maps[meta.inspectable]).toBeUndefined(); // Complex type - expect(map_of_maps[meta.name]).toBe('Map'); - expect(map_of_maps[meta.type]).toBe('iterator'); - expect(map_of_maps[0][meta.type]).toBe('array'); - expect(map_of_maps[meta.preview_long]).toBe( - 'Map(2) {"first" => Map(2), "second" => Map(2)}', - ); - expect(map_of_maps[meta.preview_short]).toBe('Map(2)'); - - expect(object_of_objects.inner[meta.size]).toBe(3); - expect(object_of_objects.inner[meta.inspectable]).toBe(true); - expect(object_of_objects.inner[meta.name]).toBe(''); - expect(object_of_objects.inner[meta.type]).toBe('object'); - expect(object_of_objects.inner[meta.preview_long]).toBe( - '{boolean: true, number: 123, string: "abc"}', - ); - expect(object_of_objects.inner[meta.preview_short]).toBe('{…}'); - - expect(object_with_symbol['Symbol(name)']).toBe('hello'); - - expect(proxy[meta.inspectable]).toBe(false); - expect(proxy[meta.name]).toBe('function'); - expect(proxy[meta.type]).toBe('function'); - expect(proxy[meta.preview_long]).toBe('ƒ () {}'); - expect(proxy[meta.preview_short]).toBe('ƒ () {}'); - - expect(react_element[meta.inspectable]).toBe(false); - expect(react_element[meta.name]).toBe('span'); - expect(react_element[meta.type]).toBe('react_element'); - expect(react_element[meta.preview_long]).toBe(''); - expect(react_element[meta.preview_short]).toBe(''); - - expect(regexp[meta.inspectable]).toBe(false); - expect(regexp[meta.name]).toBe('/abc/giu'); - expect(regexp[meta.preview_long]).toBe('/abc/giu'); - expect(regexp[meta.preview_short]).toBe('/abc/giu'); - expect(regexp[meta.type]).toBe('regexp'); - - expect(set[meta.inspectable]).toBeUndefined(); // Complex type - expect(set[meta.name]).toBe('Set'); - expect(set[meta.type]).toBe('iterator'); - expect(set[0]).toBe('abc'); - expect(set[1]).toBe(123); - expect(set[meta.preview_long]).toBe('Set(2) {"abc", 123}'); - expect(set[meta.preview_short]).toBe('Set(2)'); - - expect(set_of_sets[meta.inspectable]).toBeUndefined(); // Complex type - expect(set_of_sets[meta.name]).toBe('Set'); - expect(set_of_sets[meta.type]).toBe('iterator'); - expect(set_of_sets['0'][meta.inspectable]).toBe(true); - expect(set_of_sets[meta.preview_long]).toBe('Set(2) {Set(3), Set(3)}'); - expect(set_of_sets[meta.preview_short]).toBe('Set(2)'); - - expect(symbol[meta.inspectable]).toBe(false); - expect(symbol[meta.name]).toBe('Symbol(symbol)'); - expect(symbol[meta.type]).toBe('symbol'); - expect(symbol[meta.preview_long]).toBe('Symbol(symbol)'); - expect(symbol[meta.preview_short]).toBe('Symbol(symbol)'); - - expect(typed_array[meta.inspectable]).toBeUndefined(); // Complex type - expect(typed_array[meta.size]).toBe(3); - expect(typed_array[meta.name]).toBe('Int8Array'); - expect(typed_array[meta.type]).toBe('typed_array'); - expect(typed_array[0]).toBe(100); - expect(typed_array[1]).toBe(-100); - expect(typed_array[2]).toBe(0); - expect(typed_array[meta.preview_long]).toBe('Int8Array(3) [100, -100, 0]'); - expect(typed_array[meta.preview_short]).toBe('Int8Array(3)'); + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "anonymous_fn": Dehydrated { + "preview_short": ƒ () {}, + "preview_long": ƒ () {}, + }, + "array_buffer": Dehydrated { + "preview_short": ArrayBuffer(3), + "preview_long": ArrayBuffer(3), + }, + "array_of_arrays": Array [ + Dehydrated { + "preview_short": Array(2), + "preview_long": [Array(3), Array(0)], + }, + ], + "big_int": Dehydrated { + "preview_short": 123n, + "preview_long": 123n, + }, + "bound_fn": Dehydrated { + "preview_short": ƒ bound exampleFunction() {}, + "preview_long": ƒ bound exampleFunction() {}, + }, + "data_view": Dehydrated { + "preview_short": DataView(3), + "preview_long": DataView(3), + }, + "date": Dehydrated { + "preview_short": Tue Dec 31 2019 23:42:42 GMT+0000 (Coordinated Universal Time), + "preview_long": Tue Dec 31 2019 23:42:42 GMT+0000 (Coordinated Universal Time), + }, + "fn": Dehydrated { + "preview_short": ƒ exampleFunction() {}, + "preview_long": ƒ exampleFunction() {}, + }, + "html_element": Dehydrated { + "preview_short": , + "preview_long": , + }, + "immutable": Object { + "0": Dehydrated { + "preview_short": Array(2), + "preview_long": ["a", List(3)], + }, + "1": Dehydrated { + "preview_short": Array(2), + "preview_long": ["b", 123], + }, + "2": Dehydrated { + "preview_short": Array(2), + "preview_long": ["c", Map(2)], + }, + }, + "map": Object { + "0": Dehydrated { + "preview_short": Array(2), + "preview_long": ["name", "Brian"], + }, + "1": Dehydrated { + "preview_short": Array(2), + "preview_long": ["food", "sushi"], + }, + }, + "map_of_maps": Object { + "0": Dehydrated { + "preview_short": Array(2), + "preview_long": ["first", Map(2)], + }, + "1": Dehydrated { + "preview_short": Array(2), + "preview_long": ["second", Map(2)], + }, + }, + "object_of_objects": Object { + "inner": Dehydrated { + "preview_short": {…}, + "preview_long": {boolean: true, number: 123, string: "abc"}, + }, + }, + "object_with_symbol": Object { + "Symbol(name)": "hello", + }, + "proxy": Dehydrated { + "preview_short": ƒ () {}, + "preview_long": ƒ () {}, + }, + "react_element": Dehydrated { + "preview_short": , + "preview_long": , + }, + "regexp": Dehydrated { + "preview_short": /abc/giu, + "preview_long": /abc/giu, + }, + "set": Object { + "0": "abc", + "1": 123, + }, + "set_of_sets": Object { + "0": Dehydrated { + "preview_short": Set(3), + "preview_long": Set(3) {"a", "b", "c"}, + }, + "1": Dehydrated { + "preview_short": Set(3), + "preview_long": Set(3) {1, 2, 3}, + }, + }, + "symbol": Dehydrated { + "preview_short": Symbol(symbol), + "preview_long": Symbol(symbol), + }, + "typed_array": Object { + "0": 100, + "1": -100, + "2": 0, + }, + } + `); }); it('should not consume iterables while inspecting', async () => { @@ -725,13 +676,14 @@ describe('InspectedElement', () => { ); const inspectedElement = await inspectElementAtIndex(0); - - const {prop} = (inspectedElement: any).props; - expect(prop[meta.inspectable]).toBe(false); - expect(prop[meta.name]).toBe('Generator'); - expect(prop[meta.type]).toBe('opaque_iterator'); - expect(prop[meta.preview_long]).toBe('Generator'); - expect(prop[meta.preview_short]).toBe('Generator'); + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "prop": Dehydrated { + "preview_short": Generator, + "preview_long": Generator, + }, + } + `); }); it('should support objects with no prototype', async () => { @@ -774,10 +726,14 @@ describe('InspectedElement', () => { const inspectedElement = await inspectElementAtIndex(0); - // TRICKY: Don't use toMatchInlineSnapshot() for this test! - // Our snapshot serializer relies on hasOwnProperty() for feature detection. - expect(inspectedElement.props.object.name).toBe('blah'); - expect(inspectedElement.props.object.hasOwnProperty).toBe(true); + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "object": Object { + "hasOwnProperty": true, + "name": "blah", + }, + } + `); }); it('should support custom objects with enumerable properties and getters', async () => { @@ -1834,8 +1790,8 @@ describe('InspectedElement', () => { ReactDOM.render(