From d422a4fd714655ca04f1888f5cfe4cab9a3d88ef Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 12 Feb 2024 21:38:38 -0500 Subject: [PATCH] Always use includeHooksSource option This option was added defensively but it's not needed. There's no cost to including it always. I suspect this optional was added mainly to avoid needing to update tests. That's not a reason to have an unnecessary public API though. We have a praxis for dealing with source location in tests to avoid them failing tests. --- .../react-debug-tools/src/ReactDebugHooks.js | 53 +- .../__tests__/ReactHooksInspection-test.js | 722 ++++-- .../ReactHooksInspectionIntegration-test.js | 2295 ++++++++++++----- .../src/backend/renderer.js | 1 - .../hooks/__tests__/parseHookNames-test.js | 4 +- 5 files changed, 2096 insertions(+), 979 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 962d7d8bba2b5..2de0711331814 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -570,7 +570,7 @@ export type HooksNode = { value: mixed, subHooks: Array, debugInfo: null | ReactDebugInfo, - hookSource?: HookSource, + hookSource: null | HookSource, }; export type HooksTree = Array; @@ -717,7 +717,6 @@ function parseCustomHookName(functionName: void | string): string { function buildTree( rootStack: any, readHookLog: Array, - includeHooksSource: boolean, ): HooksTree { const rootChildren: Array = []; let prevStack = null; @@ -761,16 +760,13 @@ function buildTree( value: undefined, subHooks: children, debugInfo: null, - }; - - if (includeHooksSource) { - levelChild.hookSource = { + hookSource: { lineNumber: stackFrame.lineNumber, columnNumber: stackFrame.columnNumber, functionName: stackFrame.functionName, fileName: stackFrame.fileName, - }; - } + }, + }; levelChildren.push(levelChild); stackOfChildren.push(levelChildren); @@ -801,26 +797,25 @@ function buildTree( value: hook.value, subHooks: [], debugInfo: debugInfo, + hookSource: null, }; - if (includeHooksSource) { - const hookSource: HookSource = { - lineNumber: null, - functionName: null, - fileName: null, - columnNumber: null, - }; - if (stack && stack.length >= 1) { - const stackFrame = stack[0]; - hookSource.lineNumber = stackFrame.lineNumber; - hookSource.functionName = stackFrame.functionName; - hookSource.fileName = stackFrame.fileName; - hookSource.columnNumber = stackFrame.columnNumber; - } - - levelChild.hookSource = hookSource; + const hookSource: HookSource = { + lineNumber: null, + functionName: null, + fileName: null, + columnNumber: null, + }; + if (stack && stack.length >= 1) { + const stackFrame = stack[0]; + hookSource.lineNumber = stackFrame.lineNumber; + hookSource.functionName = stackFrame.functionName; + hookSource.fileName = stackFrame.fileName; + hookSource.columnNumber = stackFrame.columnNumber; } + levelChild.hookSource = hookSource; + levelChildren.push(levelChild); } @@ -898,7 +893,6 @@ export function inspectHooks( renderFunction: Props => React$Node, props: Props, currentDispatcher: ?CurrentDispatcherRef, - includeHooksSource: boolean = false, ): HooksTree { // DevTools will pass the current renderer's injected dispatcher. // Other apps might compile debug hooks as part of their app though. @@ -924,7 +918,7 @@ export function inspectHooks( currentDispatcher.current = previousDispatcher; } const rootStack = ErrorStackParser.parse(ancestorStackError); - return buildTree(rootStack, readHookLog, includeHooksSource); + return buildTree(rootStack, readHookLog); } function setupContexts(contextMap: Map, any>, fiber: Fiber) { @@ -953,7 +947,6 @@ function inspectHooksOfForwardRef( props: Props, ref: Ref, currentDispatcher: CurrentDispatcherRef, - includeHooksSource: boolean, ): HooksTree { const previousDispatcher = currentDispatcher.current; let readHookLog; @@ -970,7 +963,7 @@ function inspectHooksOfForwardRef( currentDispatcher.current = previousDispatcher; } const rootStack = ErrorStackParser.parse(ancestorStackError); - return buildTree(rootStack, readHookLog, includeHooksSource); + return buildTree(rootStack, readHookLog); } function resolveDefaultProps(Component: any, baseProps: any) { @@ -991,7 +984,6 @@ function resolveDefaultProps(Component: any, baseProps: any) { export function inspectHooksOfFiber( fiber: Fiber, currentDispatcher: ?CurrentDispatcherRef, - includeHooksSource: boolean = false, ): HooksTree { // DevTools will pass the current renderer's injected dispatcher. // Other apps might compile debug hooks as part of their app though. @@ -1033,11 +1025,10 @@ export function inspectHooksOfFiber( props, fiber.ref, currentDispatcher, - includeHooksSource, ); } - return inspectHooks(type, props, currentDispatcher, includeHooksSource); + return inspectHooks(type, props, currentDispatcher); } finally { currentFiber = null; currentHook = null; diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js index 4846a1fb20750..9b8c2940270a8 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js @@ -13,6 +13,18 @@ let React; let ReactDebugTools; +function normalizeSourceLoc(tree) { + tree.forEach(node => { + if (node.hookSource) { + node.hookSource.fileName = '**'; + node.hookSource.lineNumber = 0; + node.hookSource.columnNumber = 0; + } + normalizeSourceLoc(node.subHooks); + }); + return tree; +} + describe('ReactHooksInspection', () => { beforeEach(() => { React = require('react'); @@ -25,16 +37,24 @@ describe('ReactHooksInspection', () => { return
{state}
; } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'hello world', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello world", + }, + ] + `); }); it('should inspect a simple custom hook', () => { @@ -48,25 +68,75 @@ describe('ReactHooksInspection', () => { return
{value}
; } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: __DEV__ ? 'custom hook label' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello world", + }, + ], + "value": "custom hook label", + }, + ] + `); + } else { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: true, - id: 0, - name: 'State', - value: 'hello world', - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello world", + }, + ], + "value": undefined, }, - ], - }, - ]); + ] + `); + } }); it('should inspect a tree of multiple hooks', () => { @@ -86,58 +156,96 @@ describe('ReactHooksInspection', () => { ); } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: true, - id: 0, - name: 'State', - debugInfo: null, - subHooks: [], - value: 'hello', - }, - { - isStateEditable: false, - id: 1, - name: 'Effect', - debugInfo: null, - subHooks: [], - value: effect, - }, - ], - }, - { - isStateEditable: false, - id: null, - name: 'Custom', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: true, - id: 2, - name: 'State', - value: 'world', - debugInfo: null, - subHooks: [], + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, }, - { - isStateEditable: false, - id: 3, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, }, - ], - }, - ]); + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "world", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + ], + "value": undefined, + }, + ] + `); }); it('should inspect a tree of multiple levels of hooks', () => { @@ -167,92 +275,154 @@ describe('ReactHooksInspection', () => { ); } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Bar', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: true, - id: 0, - name: 'Reducer', - value: 'hello', - debugInfo: null, - subHooks: [], + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Bar", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useBar", + "lineNumber": 0, }, - { - isStateEditable: false, - id: 1, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "hello", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useBar", + "lineNumber": 0, }, - ], - }, - { - isStateEditable: false, - id: 2, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - ], - }, - { - isStateEditable: false, - id: null, - name: 'Baz', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: false, - id: 3, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], + "id": 2, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, }, - { - isStateEditable: false, - id: null, - name: 'Custom', - debugInfo: null, - subHooks: [ - { - isStateEditable: true, - id: 4, - name: 'Reducer', - debugInfo: null, - subHooks: [], - value: 'world', + "id": null, + "isStateEditable": false, + "name": "Baz", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useBaz", + "lineNumber": 0, }, - { - isStateEditable: false, - id: 5, - name: 'Effect', - debugInfo: null, - subHooks: [], - value: effect, + "id": 3, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useBaz", + "lineNumber": 0, }, - ], - value: undefined, - }, - ], - }, - ]); + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 4, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "world", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 5, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + ], + "value": undefined, + }, + ], + "value": undefined, + }, + ] + `); }); it('should inspect the default value using the useContext hook', () => { @@ -262,16 +432,24 @@ describe('ReactHooksInspection', () => { return
{value}
; } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Context', - value: 'default', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Context", + "subHooks": [], + "value": "default", + }, + ] + `); }); it('should support an injected dispatcher', () => { @@ -330,41 +508,71 @@ describe('ReactHooksInspection', () => { ); } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Context', - value: 'hi', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: null, - name: 'Custom', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: false, - id: null, - name: 'Promise', - value: 'world', - debugInfo: [{name: 'Hello'}], - subHooks: [], + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, }, - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'world', - debugInfo: null, - subHooks: [], + "id": null, + "isStateEditable": false, + "name": "Context", + "subHooks": [], + "value": "hi", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, }, - ], - }, - ]); + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": [ + { + "name": "Hello", + }, + ], + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Promise", + "subHooks": [], + "value": "world", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "world", + }, + ], + "value": undefined, + }, + ] + `); }); it('should inspect use() calls for unresolved Promise', () => { @@ -375,16 +583,24 @@ describe('ReactHooksInspection', () => { return
{value}
; } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Unresolved', - value: promise, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Unresolved", + "subHooks": [], + "value": Promise {}, + }, + ] + `); }); describe('useDebugValue', () => { @@ -407,25 +623,75 @@ describe('ReactHooksInspection', () => { return null; } const tree = ReactDebugTools.inspectHooks(Foo, {}); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: __DEV__ ? 'bar:123' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": "bar:123", + }, + ] + `); + } else { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: true, - id: 0, - name: 'State', - debugInfo: null, - subHooks: [], - value: 0, + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, }, - ], - }, - ]); + ] + `); + } }); }); }); diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index b6224f2dfa76e..9c7bc4415c140 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -17,6 +17,18 @@ let ReactDebugTools; let act; let useMemoCache; +function normalizeSourceLoc(tree) { + tree.forEach(node => { + if (node.hookSource) { + node.hookSource.fileName = '**'; + node.hookSource.lineNumber = 0; + node.hookSource.columnNumber = 0; + } + normalizeSourceLoc(node.subHooks); + }); + return tree; +} + describe('ReactHooksInspectionIntegration', () => { beforeEach(() => { React = require('react'); @@ -42,24 +54,38 @@ describe('ReactHooksInspectionIntegration', () => { let childFiber = renderer.root.findByType(Foo)._currentFiber(); let tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'hello', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'State', - value: 'world', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "world", + }, + ] + `); const {onMouseDown: setStateA, onMouseUp: setStateB} = renderer.root.findByType('div').props; @@ -69,48 +95,76 @@ describe('ReactHooksInspectionIntegration', () => { childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'Hi', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'State', - value: 'world', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "Hi", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "world", + }, + ] + `); await act(() => setStateB('world!')); childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'Hi', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'State', - value: 'world!', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "Hi", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "world!", + }, + ] + `); }); it('should inspect the current state of all stateful hooks', async () => { @@ -157,72 +211,122 @@ describe('ReactHooksInspectionIntegration', () => { const {onClick: updateStates} = renderer.root.findByType('div').props; let tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'a', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'Reducer', - value: 'b', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 2, - name: 'Ref', - value: 'c', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 3, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 4, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 5, - name: 'ImperativeHandle', - value: outsideRef.current, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 6, - name: 'Memo', - value: 'ab', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 7, - name: 'Callback', - value: updateStates, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "a", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "b", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Ref", + "subHooks": [], + "value": "c", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 4, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 5, + "isStateEditable": false, + "name": "ImperativeHandle", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 6, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "ab", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 7, + "isStateEditable": false, + "name": "Callback", + "subHooks": [], + "value": [Function], + }, + ] + `); await act(() => { updateStates(); @@ -231,72 +335,122 @@ describe('ReactHooksInspectionIntegration', () => { childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'A', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'Reducer', - value: 'B', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 2, - name: 'Ref', - value: 'C', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 3, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 4, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 5, - name: 'ImperativeHandle', - value: outsideRef.current, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 6, - name: 'Memo', - value: 'Ab', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 7, - name: 'Callback', - value: updateStates, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "A", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "B", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Ref", + "subHooks": [], + "value": "C", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 4, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 5, + "isStateEditable": false, + "name": "ImperativeHandle", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 6, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "Ab", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 7, + "isStateEditable": false, + "name": "Callback", + "subHooks": [], + "value": [Function], + }, + ] + `); }); it('should inspect the current state of all stateful hooks, including useInsertionEffect', async () => { @@ -345,80 +499,136 @@ describe('ReactHooksInspectionIntegration', () => { const {onClick: updateStates} = renderer.root.findByType('div').props; let tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'a', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'Reducer', - value: 'b', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 2, - name: 'Ref', - value: 'c', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 3, - name: 'InsertionEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 4, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 5, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 6, - name: 'ImperativeHandle', - value: outsideRef.current, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 7, - name: 'Memo', - value: 'ab', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 8, - name: 'Callback', - value: updateStates, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "a", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "b", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Ref", + "subHooks": [], + "value": "c", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": false, + "name": "InsertionEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 4, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 5, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 6, + "isStateEditable": false, + "name": "ImperativeHandle", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 7, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "ab", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 8, + "isStateEditable": false, + "name": "Callback", + "subHooks": [], + "value": [Function], + }, + ] + `); await act(() => { updateStates(); @@ -427,80 +637,136 @@ describe('ReactHooksInspectionIntegration', () => { childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'A', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 1, - name: 'Reducer', - value: 'B', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 2, - name: 'Ref', - value: 'C', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 3, - name: 'InsertionEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 4, - name: 'LayoutEffect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 5, - name: 'Effect', - value: effect, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 6, - name: 'ImperativeHandle', - value: outsideRef.current, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 7, - name: 'Memo', - value: 'Ab', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: 8, - name: 'Callback', - value: updateStates, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "A", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "Reducer", + "subHooks": [], + "value": "B", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Ref", + "subHooks": [], + "value": "C", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": false, + "name": "InsertionEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 4, + "isStateEditable": false, + "name": "LayoutEffect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 5, + "isStateEditable": false, + "name": "Effect", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 6, + "isStateEditable": false, + "name": "ImperativeHandle", + "subHooks": [], + "value": [Function], + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 7, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "Ab", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 8, + "isStateEditable": false, + "name": "Callback", + "subHooks": [], + "value": [Function], + }, + ] + `); }); it('should inspect the value of the current provider in useContext', () => { @@ -516,16 +782,24 @@ describe('ReactHooksInspectionIntegration', () => { ); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Context', - value: 'contextual', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Context", + "subHooks": [], + "value": "contextual", + }, + ] + `); }); it('should inspect forwardRef', () => { @@ -539,16 +813,24 @@ describe('ReactHooksInspectionIntegration', () => { const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: 0, - name: 'ImperativeHandle', - value: obj, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": undefined, + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "ImperativeHandle", + "subHooks": [], + "value": [Function], + }, + ] + `); }); it('should inspect memo', () => { @@ -561,16 +843,24 @@ describe('ReactHooksInspectionIntegration', () => { // TODO: Test renderer findByType is broken for memo. Have to search for the inner. const childFiber = renderer.root.findByType(InnerFoo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'hello', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "InnerFoo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello", + }, + ] + `); }); it('should inspect custom hooks', () => { @@ -585,25 +875,39 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: undefined, - debugInfo: null, - subHooks: [ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'hello', - debugInfo: null, - subHooks: [], - }, - ], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello", + }, + ], + "value": undefined, + }, + ] + `); }); it('should support composite useTransition hook', () => { @@ -616,32 +920,52 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: 0, - isStateEditable: false, - name: 'Transition', - value: undefined, - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 'hello', - debugInfo: null, - subHooks: [], - }, - { - id: 2, - isStateEditable: false, - name: 'Memo', - value: 'not used', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": null, + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "Transition", + "subHooks": [], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "hello", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "not used", + }, + ] + `); }); it('should support useDeferredValue hook', () => { @@ -654,32 +978,52 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: 0, - isStateEditable: false, - name: 'DeferredValue', - value: 'abc', - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 1, - debugInfo: null, - subHooks: [], - }, - { - id: 2, - isStateEditable: false, - name: 'Memo', - value: 2, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": null, + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "DeferredValue", + "subHooks": [], + "value": "abc", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": 1, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": 2, + }, + ] + `); }); it('should support useId hook', () => { @@ -700,14 +1044,22 @@ describe('ReactHooksInspectionIntegration', () => { expect(tree[0].name).toEqual('Id'); expect(String(tree[0].value).startsWith(':r')).toBe(true); - expect(tree[1]).toEqual({ - id: 1, - isStateEditable: true, - name: 'State', - value: 'hello', - debugInfo: null, - subHooks: [], - }); + expect(normalizeSourceLoc(tree)[1]).toMatchInlineSnapshot(` + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "hello", + } + `); }); describe('useMemoCache', () => { @@ -791,67 +1143,218 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Example)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'LabeledValue', - value: __DEV__ ? 'custom label a' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: true, - id: 0, - name: 'State', - value: 'a', - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "LabeledValue", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useLabeledValue", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "a", + }, + ], + "value": "custom label a", }, - ], - }, - { - isStateEditable: true, - id: 1, - name: 'State', - value: 'b', - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: false, - id: null, - name: 'Anonymous', - value: undefined, - debugInfo: null, - subHooks: [ { - isStateEditable: true, - id: 2, - name: 'State', - value: 'c', - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "b", }, - ], - }, - { - isStateEditable: false, - id: null, - name: 'LabeledValue', - value: __DEV__ ? 'custom label d' : undefined, - debugInfo: null, - subHooks: [ { - isStateEditable: true, - id: 3, - name: 'State', - value: 'd', - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Anonymous", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useAnonymous", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "c", + }, + ], + "value": undefined, }, - ], - }, - ]); + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "LabeledValue", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useLabeledValue", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "d", + }, + ], + "value": "custom label d", + }, + ] + `); + } else + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "LabeledValue", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useLabeledValue", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "a", + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "b", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Anonymous", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useAnonymous", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "c", + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "LabeledValue", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useLabeledValue", + "lineNumber": 0, + }, + "id": 3, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "d", + }, + ], + "value": undefined, + }, + ] + `); }); it('should support inspectable values for nested custom hooks', () => { @@ -870,34 +1373,104 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Example)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Outer', - value: __DEV__ ? 'outer' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: false, - id: null, - name: 'Inner', - value: __DEV__ ? 'inner' : undefined, - debugInfo: null, - subHooks: [ + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Outer", + "subHooks": [ { - isStateEditable: true, - id: 0, - name: 'State', - value: 0, - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useOuter", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Inner", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useInner", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": "inner", }, ], + "value": "outer", }, - ], - }, - ]); + ] + `); + } else + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Outer", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useOuter", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Inner", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useInner", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, + }, + ], + "value": undefined, + }, + ] + `); }); it('should support multiple inspectable values per custom hooks', () => { @@ -920,59 +1493,194 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Example)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'SingleLabelCustom', - value: __DEV__ ? 'single one' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: true, - id: 0, - name: 'State', - value: 0, - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "SingleLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useSingleLabelCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": "single one", }, - ], - }, - { - isStateEditable: false, - id: null, - name: 'MultiLabelCustom', - value: __DEV__ ? ['one', 'two', 'three'] : undefined, - debugInfo: null, - subHooks: [ { - isStateEditable: true, - id: 1, - name: 'State', - value: 0, - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "MultiLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useMultiLabelCustom", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": [ + "one", + "two", + "three", + ], }, - ], - }, - { - isStateEditable: false, - id: null, - name: 'SingleLabelCustom', - value: __DEV__ ? 'single two' : undefined, - debugInfo: null, - subHooks: [ { - isStateEditable: true, - id: 2, - name: 'State', - value: 0, - debugInfo: null, - subHooks: [], + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "SingleLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useSingleLabelCustom", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": "single two", }, - ], - }, - ]); + ] + `); + } else + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "SingleLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useSingleLabelCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "MultiLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useMultiLabelCustom", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "SingleLabelCustom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useSingleLabelCustom", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, + }, + ] + `); }); it('should ignore useDebugValue() made outside of a custom hook', () => { @@ -998,25 +1706,74 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Example)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Custom', - value: __DEV__ ? 'bar:123' : undefined, - debugInfo: null, - subHooks: [ + if (__DEV__) { + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": "bar:123", + }, + ] + `); + } else + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ { - isStateEditable: true, - id: 0, - name: 'State', - debugInfo: null, - subHooks: [], - value: 0, + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Example", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Custom", + "subHooks": [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "useCustom", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": 0, + }, + ], + "value": undefined, }, - ], - }, - ]); + ] + `); }); }); @@ -1051,16 +1808,24 @@ describe('ReactHooksInspectionIntegration', () => { const childFiber = renderer.root._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: true, - id: 0, - name: 'State', - value: 'def', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": "def", + }, + ] + `); }); it('should support an injected dispatcher', () => { @@ -1145,24 +1910,40 @@ describe('ReactHooksInspectionIntegration', () => { const childFiber = renderer.root._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - isStateEditable: false, - id: null, - name: 'Context', - value: 1, - debugInfo: null, - subHooks: [], - }, - { - isStateEditable: true, - id: 0, - name: 'State', - value: {count: 2}, - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Context", + "subHooks": [], + "value": 1, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": true, + "name": "State", + "subHooks": [], + "value": { + "count": 2, + }, + }, + ] + `); }); it('should support composite useSyncExternalStore hook', () => { @@ -1180,32 +1961,52 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: 0, - isStateEditable: false, - name: 'SyncExternalStore', - value: 'snapshot', - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 'memo', - debugInfo: null, - subHooks: [], - }, - { - id: 2, - isStateEditable: false, - name: 'Memo', - value: 'not used', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": null, + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "SyncExternalStore", + "subHooks": [], + "value": "snapshot", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "memo", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "not used", + }, + ] + `); }); it('should support use(Context) hook', () => { @@ -1221,32 +2022,52 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: null, - isStateEditable: false, - name: 'Context', - value: 'default', - debugInfo: null, - subHooks: [], - }, - { - id: 0, - isStateEditable: false, - name: 'Memo', - value: 'memo', - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 'not used', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": null, + "isStateEditable": false, + "name": "Context", + "subHooks": [], + "value": "default", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "memo", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "not used", + }, + ] + `); }); // @gate enableAsyncActions @@ -1262,32 +2083,52 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: 0, - isStateEditable: false, - name: 'Optimistic', - value: 'abc', - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 'memo', - debugInfo: null, - subHooks: [], - }, - { - id: 2, - isStateEditable: false, - name: 'Memo', - value: 'not used', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "Optimistic", + "subHooks": [], + "value": "abc", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "memo", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "not used", + }, + ] + `); }); // @gate enableFormActions && enableAsyncActions @@ -1305,31 +2146,51 @@ describe('ReactHooksInspectionIntegration', () => { const renderer = ReactTestRenderer.create(); const childFiber = renderer.root.findByType(Foo)._currentFiber(); const tree = ReactDebugTools.inspectHooksOfFiber(childFiber); - expect(tree).toEqual([ - { - id: 0, - isStateEditable: false, - name: 'FormState', - value: 0, - debugInfo: null, - subHooks: [], - }, - { - id: 1, - isStateEditable: false, - name: 'Memo', - value: 'memo', - debugInfo: null, - subHooks: [], - }, - { - id: 2, - isStateEditable: false, - name: 'Memo', - value: 'not used', - debugInfo: null, - subHooks: [], - }, - ]); + expect(normalizeSourceLoc(tree)).toMatchInlineSnapshot(` + [ + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 0, + "isStateEditable": false, + "name": "FormState", + "subHooks": [], + "value": 0, + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 1, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "memo", + }, + { + "debugInfo": null, + "hookSource": { + "columnNumber": 0, + "fileName": "**", + "functionName": "Foo", + "lineNumber": 0, + }, + "id": 2, + "isStateEditable": false, + "name": "Memo", + "subHooks": [], + "value": "not used", + }, + ] + `); }); }); diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 069cde215a1ca..b23a84ce35fe4 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -3252,7 +3252,6 @@ export function attach( hooks = inspectHooksOfFiber( fiber, (renderer.currentDispatcherRef: any), - true, // Include source location info for hooks ); } finally { // Restore original console functionality. diff --git a/packages/react-devtools-shared/src/hooks/__tests__/parseHookNames-test.js b/packages/react-devtools-shared/src/hooks/__tests__/parseHookNames-test.js index 254a17717fbc4..5e9397456ee06 100644 --- a/packages/react-devtools-shared/src/hooks/__tests__/parseHookNames-test.js +++ b/packages/react-devtools-shared/src/hooks/__tests__/parseHookNames-test.js @@ -96,7 +96,7 @@ describe('parseHookNames', () => { }); async function getHookNamesForComponent(Component, props = {}) { - const hooksTree = inspectHooks(Component, props, undefined, true); + const hooksTree = inspectHooks(Component, props, undefined); const hookNames = await parseHookNames(hooksTree); return hookNames; } @@ -926,7 +926,7 @@ describe('parseHookNames worker', () => { }); async function getHookNamesForComponent(Component, props = {}) { - const hooksTree = inspectHooks(Component, props, undefined, true); + const hooksTree = inspectHooks(Component, props, undefined); const hookNames = await parseHookNames(hooksTree); return hookNames; }