Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 8 additions & 70 deletions packages/react-native/Libraries/LogBox/UI/LogBoxInspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<LogBoxLog>,
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;
Expand All @@ -54,7 +51,7 @@ function LogBoxInspector(props: Props): React.Node {
}
}, [logs, selectedIndex]);

React.useEffect(() => {
useEffect(() => {
Keyboard.dismiss();
}, []);

Expand Down Expand Up @@ -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 (
<>
<LogBoxInspectorMessageHeader
collapsed={collapsed}
onPress={() => setCollapsed(!collapsed)}
message={props.log.message}
level={props.log.level}
title={headerTitle}
/>
<ScrollView style={styles.scrollBody}>
<LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
<LogBoxInspectorReactFrames log={props.log} />
<LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
</ScrollView>
</>
);
}
return (
<ScrollView style={styles.scrollBody}>
<LogBoxInspectorMessageHeader
collapsed={collapsed}
onPress={() => setCollapsed(!collapsed)}
message={props.log.message}
level={props.log.level}
title={headerTitle}
/>
<LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
<LogBoxInspectorReactFrames log={props.log} />
<LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
</ScrollView>
);
}

const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: LogBoxStyle.getTextColor(),
},
scrollBody: {
backgroundColor: LogBoxStyle.getBackgroundColor(0.9),
flex: 1,
},
});

export default LogBoxInspector;
87 changes: 87 additions & 0 deletions packages/react-native/Libraries/LogBox/UI/LogBoxInspectorBody.js
Original file line number Diff line number Diff line change
@@ -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 (
<>
<LogBoxInspectorMessageHeader
collapsed={collapsed}
onPress={() => setCollapsed(!collapsed)}
message={props.log.message}
level={props.log.level}
title={headerTitle}
/>
<ScrollView style={styles.scrollBody}>
<LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
<LogBoxInspectorReactFrames log={props.log} />
<LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
</ScrollView>
</>
);
}
return (
<ScrollView style={styles.scrollBody}>
<LogBoxInspectorMessageHeader
collapsed={collapsed}
onPress={() => setCollapsed(!collapsed)}
message={props.log.message}
level={props.log.level}
title={headerTitle}
/>
<LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
<LogBoxInspectorReactFrames log={props.log} />
<LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
</ScrollView>
);
}

const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: LogBoxStyle.getTextColor(),
},
scrollBody: {
backgroundColor: LogBoxStyle.getBackgroundColor(0.9),
flex: 1,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ const render = require('../../../../jest/renderer');
const LogBoxButton = require('../LogBoxButton').default;
const React = require('react');

// Mock `TouchableWithoutFeedback` because we are interested in snapshotting the
// behavior of `LogBoxButton`, not `TouchableWithoutFeedback`.
jest.mock('../../../Components/Touchable/TouchableWithoutFeedback', () => ({
__esModule: true,
default: 'TouchableWithoutFeedback',
}));

describe('LogBoxButton', () => {
it('should render only a view without an onPress', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxButton
backgroundColor={{
default: 'black',
Expand All @@ -31,7 +38,7 @@ describe('LogBoxButton', () => {
});

it('should render TouchableWithoutFeedback and pass through props', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxButton
backgroundColor={{
default: 'black',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -54,7 +69,7 @@ const logs = [

describe('LogBoxContainer', () => {
it('should render null with no logs', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxInspector
onDismiss={() => {}}
onMinimize={() => {}}
Expand All @@ -68,7 +83,7 @@ describe('LogBoxContainer', () => {
});

it('should render warning with selectedIndex 0', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxInspector
onDismiss={() => {}}
onMinimize={() => {}}
Expand All @@ -82,7 +97,7 @@ describe('LogBoxContainer', () => {
});

it('should render fatal with selectedIndex 2', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxInspector
onDismiss={() => {}}
onMinimize={() => {}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,34 @@ const render = require('../../../../jest/renderer');
const LogBoxInspectorCodeFrame = require('../LogBoxInspectorCodeFrame').default;
const React = require('react');

// Mock child components because we are interested in snapshotting the behavior
// of `LogBoxInspectorCodeFrame`, not its children.
jest.mock('../../../Components/ScrollView/ScrollView', () => ({
__esModule: true,
default: 'ScrollView',
}));
jest.mock('../AnsiHighlight', () => ({
__esModule: true,
default: 'Ansi',
}));
jest.mock('../LogBoxButton', () => ({
__esModule: true,
default: 'LogBoxButton',
}));
jest.mock('../LogBoxInspectorSection', () => ({
__esModule: true,
default: 'LogBoxInspectorSection',
}));

describe('LogBoxInspectorCodeFrame', () => {
it('should render null for no code frame', () => {
const output = render.shallowRender(
<LogBoxInspectorCodeFrame codeFrame={null} />,
);
const output = render.create(<LogBoxInspectorCodeFrame codeFrame={null} />);

expect(output).toMatchSnapshot();
});

it('should render a code frame', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxInspectorCodeFrame
codeFrame={{
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
Expand All @@ -43,7 +60,7 @@ describe('LogBoxInspectorCodeFrame', () => {
});

it('should render a code frame without a location', () => {
const output = render.shallowRender(
const output = render.create(
<LogBoxInspectorCodeFrame
codeFrame={{
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
Expand Down
Loading