diff --git a/packages/react-native/Libraries/LogBox/UI/LogBoxInspector.js b/packages/react-native/Libraries/LogBox/UI/LogBoxInspector.js index 110e411b62a..ae6ddbc551f 100644 --- a/packages/react-native/Libraries/LogBox/UI/LogBoxInspector.js +++ b/packages/react-native/Libraries/LogBox/UI/LogBoxInspector.js @@ -9,40 +9,37 @@ */ import Keyboard from '../../Components/Keyboard/Keyboard'; -import ScrollView from '../../Components/ScrollView/ScrollView'; import View from '../../Components/View/View'; import StyleSheet from '../../StyleSheet/StyleSheet'; import * as LogBoxData from '../Data/LogBoxData'; import LogBoxLog, {type LogLevel} from '../Data/LogBoxLog'; -import LogBoxInspectorCodeFrame from './LogBoxInspectorCodeFrame'; +import LogBoxInspectorBody from './LogBoxInspectorBody'; import LogBoxInspectorFooter from './LogBoxInspectorFooter'; import LogBoxInspectorHeader from './LogBoxInspectorHeader'; -import LogBoxInspectorMessageHeader from './LogBoxInspectorMessageHeader'; -import LogBoxInspectorReactFrames from './LogBoxInspectorReactFrames'; -import LogBoxInspectorStackFrames from './LogBoxInspectorStackFrames'; import * as LogBoxStyle from './LogBoxStyle'; import * as React from 'react'; +import {useEffect} from 'react'; -type Props = $ReadOnly<{| +type Props = $ReadOnly<{ onDismiss: () => void, onChangeSelectedIndex: (index: number) => void, onMinimize: () => void, logs: $ReadOnlyArray, selectedIndex: number, fatalType?: ?LogLevel, -|}>; +}>; -function LogBoxInspector(props: Props): React.Node { +export default function LogBoxInspector(props: Props): React.Node { const {logs, selectedIndex} = props; let log = logs[selectedIndex]; - React.useEffect(() => { + useEffect(() => { if (log) { LogBoxData.symbolicateLogNow(log); } }, [log]); - React.useEffect(() => { + useEffect(() => { // Optimistically symbolicate the last and next logs. if (logs.length > 1) { const selected = selectedIndex; @@ -54,7 +51,7 @@ function LogBoxInspector(props: Props): React.Node { } }, [logs, selectedIndex]); - React.useEffect(() => { + useEffect(() => { Keyboard.dismiss(); }, []); @@ -84,68 +81,9 @@ function LogBoxInspector(props: Props): React.Node { ); } -const headerTitleMap = { - warn: 'Console Warning', - error: 'Console Error', - fatal: 'Uncaught Error', - syntax: 'Syntax Error', - component: 'Render Error', -}; - -function LogBoxInspectorBody(props: {log: LogBoxLog, onRetry: () => void}) { - const [collapsed, setCollapsed] = React.useState(true); - - React.useEffect(() => { - setCollapsed(true); - }, [props.log]); - - const headerTitle = - props.log.type ?? - headerTitleMap[props.log.isComponentError ? 'component' : props.log.level]; - - if (collapsed) { - return ( - <> - setCollapsed(!collapsed)} - message={props.log.message} - level={props.log.level} - title={headerTitle} - /> - - - - - - - ); - } - return ( - - setCollapsed(!collapsed)} - message={props.log.message} - level={props.log.level} - title={headerTitle} - /> - - - - - ); -} - const styles = StyleSheet.create({ root: { flex: 1, backgroundColor: LogBoxStyle.getTextColor(), }, - scrollBody: { - backgroundColor: LogBoxStyle.getBackgroundColor(0.9), - flex: 1, - }, }); - -export default LogBoxInspector; diff --git a/packages/react-native/Libraries/LogBox/UI/LogBoxInspectorBody.js b/packages/react-native/Libraries/LogBox/UI/LogBoxInspectorBody.js new file mode 100644 index 00000000000..65af7fb2cdd --- /dev/null +++ b/packages/react-native/Libraries/LogBox/UI/LogBoxInspectorBody.js @@ -0,0 +1,87 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import ScrollView from '../../Components/ScrollView/ScrollView'; +import StyleSheet from '../../StyleSheet/StyleSheet'; +import LogBoxLog from '../Data/LogBoxLog'; +import LogBoxInspectorCodeFrame from './LogBoxInspectorCodeFrame'; +import LogBoxInspectorMessageHeader from './LogBoxInspectorMessageHeader'; +import LogBoxInspectorReactFrames from './LogBoxInspectorReactFrames'; +import LogBoxInspectorStackFrames from './LogBoxInspectorStackFrames'; +import * as LogBoxStyle from './LogBoxStyle'; +import * as React from 'react'; +import {useEffect, useState} from 'react'; + +const headerTitleMap = { + warn: 'Console Warning', + error: 'Console Error', + fatal: 'Uncaught Error', + syntax: 'Syntax Error', + component: 'Render Error', +}; + +export default function LogBoxInspectorBody(props: { + log: LogBoxLog, + onRetry: () => void, +}): React.Node { + const [collapsed, setCollapsed] = useState(true); + + useEffect(() => { + setCollapsed(true); + }, [props.log]); + + const headerTitle = + props.log.type ?? + headerTitleMap[props.log.isComponentError ? 'component' : props.log.level]; + + if (collapsed) { + return ( + <> + setCollapsed(!collapsed)} + message={props.log.message} + level={props.log.level} + title={headerTitle} + /> + + + + + + + ); + } + return ( + + setCollapsed(!collapsed)} + message={props.log.message} + level={props.log.level} + title={headerTitle} + /> + + + + + ); +} + +const styles = StyleSheet.create({ + root: { + flex: 1, + backgroundColor: LogBoxStyle.getTextColor(), + }, + scrollBody: { + backgroundColor: LogBoxStyle.getBackgroundColor(0.9), + flex: 1, + }, +}); diff --git a/packages/react-native/Libraries/LogBox/UI/__tests__/LogBoxInspector-test.js b/packages/react-native/Libraries/LogBox/UI/__tests__/LogBoxInspector-test.js index af725eb2143..49fb2a1c8a3 100644 --- a/packages/react-native/Libraries/LogBox/UI/__tests__/LogBoxInspector-test.js +++ b/packages/react-native/Libraries/LogBox/UI/__tests__/LogBoxInspector-test.js @@ -16,6 +16,21 @@ const LogBoxLog = require('../../Data/LogBoxLog').default; const LogBoxInspector = require('../LogBoxInspector').default; const React = require('react'); +// Mock child components because we are interested in snapshotting the behavior +// of `LogBoxInspector`, not its children. +jest.mock('../LogBoxInspectorBody', () => ({ + __esModule: true, + default: 'LogBoxInspectorBody', +})); +jest.mock('../LogBoxInspectorFooter', () => ({ + __esModule: true, + default: 'LogBoxInspectorFooter', +})); +jest.mock('../LogBoxInspectorHeader', () => ({ + __esModule: true, + default: 'LogBoxInspectorHeader', +})); + const logs = [ new LogBoxLog({ level: 'warn', @@ -54,7 +69,7 @@ const logs = [ describe('LogBoxContainer', () => { it('should render null with no logs', () => { - const output = render.shallowRender( + const output = render.create( {}} onMinimize={() => {}} @@ -68,7 +83,7 @@ describe('LogBoxContainer', () => { }); it('should render warning with selectedIndex 0', () => { - const output = render.shallowRender( + const output = render.create( {}} onMinimize={() => {}} @@ -82,7 +97,7 @@ describe('LogBoxContainer', () => { }); it('should render fatal with selectedIndex 2', () => { - const output = render.shallowRender( + const output = render.create( {}} onMinimize={() => {}} diff --git a/packages/react-native/Libraries/LogBox/UI/__tests__/__snapshots__/LogBoxInspector-test.js.snap b/packages/react-native/Libraries/LogBox/UI/__tests__/__snapshots__/LogBoxInspector-test.js.snap index 34f1094a348..f55f910b19e 100644 --- a/packages/react-native/Libraries/LogBox/UI/__tests__/__snapshots__/LogBoxInspector-test.js.snap +++ b/packages/react-native/Libraries/LogBox/UI/__tests__/__snapshots__/LogBoxInspector-test.js.snap @@ -35,7 +35,7 @@ exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = ` "symbolicated": Object { "error": null, "stack": null, - "status": "NONE", + "status": "PENDING", }, "symbolicatedComponentStack": Object { "componentStack": null, diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 09ad5d5308e..8ace0bdbb5e 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -5525,16 +5525,23 @@ declare export default typeof LogBoxButton; `; exports[`public API should not change unintentionally Libraries/LogBox/UI/LogBoxInspector.js 1`] = ` -"type Props = $ReadOnly<{| +"type Props = $ReadOnly<{ onDismiss: () => void, onChangeSelectedIndex: (index: number) => void, onMinimize: () => void, logs: $ReadOnlyArray, selectedIndex: number, fatalType?: ?LogLevel, -|}>; -declare function LogBoxInspector(props: Props): React.Node; -declare export default typeof LogBoxInspector; +}>; +declare export default function LogBoxInspector(props: Props): React.Node; +" +`; + +exports[`public API should not change unintentionally Libraries/LogBox/UI/LogBoxInspectorBody.js 1`] = ` +"declare export default function LogBoxInspectorBody(props: { + log: LogBoxLog, + onRetry: () => void, +}): React.Node; " `;