Add fatal handling
Summary: This diff adds handling to fatal errors such as thrown exceptions by popping them full screen and not allowing the user to dismiss them. They say that they're "Fatal Errors" and explain that "Fatal errors require a reload". Changelog: [Internal] Reviewed By: motiz88 Differential Revision: D18257185 fbshipit-source-id: ca051027b19c3cd2410ae59764d7b98a78f08dca
This commit is contained in:
Родитель
34989c88e0
Коммит
f6b1fa3197
|
@ -127,17 +127,21 @@ export function addException(error: ExceptionData): void {
|
||||||
if (lastLog && lastLog.category === category) {
|
if (lastLog && lastLog.category === category) {
|
||||||
lastLog.incrementCount();
|
lastLog.incrementCount();
|
||||||
} else {
|
} else {
|
||||||
logs.add(
|
const newLog = new LogBoxLog(
|
||||||
new LogBoxLog(
|
error.isFatal ? 'fatal' : 'error',
|
||||||
'error',
|
message,
|
||||||
message,
|
error.stack,
|
||||||
error.stack,
|
category,
|
||||||
category,
|
error.componentStack != null
|
||||||
error.componentStack != null
|
? parseComponentStack(error.componentStack)
|
||||||
? parseComponentStack(error.componentStack)
|
: [],
|
||||||
: [],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Start symbolicating now so it's warm when it renders.
|
||||||
|
if (error.isFatal) {
|
||||||
|
symbolicateLogLazy(newLog);
|
||||||
|
}
|
||||||
|
logs.add(newLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdate();
|
handleUpdate();
|
||||||
|
|
|
@ -15,7 +15,7 @@ import * as LogBoxSymbolication from './LogBoxSymbolication';
|
||||||
import type {Category, Message, ComponentStack} from './parseLogBoxLog';
|
import type {Category, Message, ComponentStack} from './parseLogBoxLog';
|
||||||
import type {Stack} from './LogBoxSymbolication';
|
import type {Stack} from './LogBoxSymbolication';
|
||||||
|
|
||||||
export type LogLevel = 'warn' | 'error';
|
export type LogLevel = 'warn' | 'error' | 'fatal';
|
||||||
|
|
||||||
export type SymbolicationRequest = $ReadOnly<{|
|
export type SymbolicationRequest = $ReadOnly<{|
|
||||||
abort: () => void,
|
abort: () => void,
|
||||||
|
|
|
@ -51,12 +51,38 @@ function LogBoxContainer(props: Props): React.Node {
|
||||||
|
|
||||||
function openLog(log: LogBoxLog) {
|
function openLog(log: LogBoxLog) {
|
||||||
let index = logs.length - 1;
|
let index = logs.length - 1;
|
||||||
|
|
||||||
|
// Stop at zero because if we don't find any log, we'll open the first log.
|
||||||
while (index > 0 && logs[index] !== log) {
|
while (index > 0 && logs[index] !== log) {
|
||||||
index -= 1;
|
index -= 1;
|
||||||
}
|
}
|
||||||
setSelectedLog(index);
|
setSelectedLog(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fatalIndex = logs.length - 1;
|
||||||
|
while (fatalIndex >= 0) {
|
||||||
|
if (logs[fatalIndex].level === 'fatal') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fatalIndex -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedLogIndex == null && fatalIndex >= 0) {
|
||||||
|
return (
|
||||||
|
<View style={StyleSheet.absoluteFill}>
|
||||||
|
<LogBoxInspector
|
||||||
|
onDismiss={handleInspectorDismiss}
|
||||||
|
onMinimize={handleInspectorMinimize}
|
||||||
|
onChangeSelectedIndex={setSelectedLog}
|
||||||
|
logs={logs}
|
||||||
|
hasFatal={true}
|
||||||
|
selectedIndex={fatalIndex}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedLogIndex != null) {
|
if (selectedLogIndex != null) {
|
||||||
return (
|
return (
|
||||||
<View style={StyleSheet.absoluteFill}>
|
<View style={StyleSheet.absoluteFill}>
|
||||||
|
@ -65,6 +91,7 @@ function LogBoxContainer(props: Props): React.Node {
|
||||||
onMinimize={handleInspectorMinimize}
|
onMinimize={handleInspectorMinimize}
|
||||||
onChangeSelectedIndex={setSelectedLog}
|
onChangeSelectedIndex={setSelectedLog}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
|
hasFatal={fatalIndex != null}
|
||||||
selectedIndex={selectedLogIndex}
|
selectedIndex={selectedLogIndex}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -32,6 +32,7 @@ type Props = $ReadOnly<{|
|
||||||
onMinimize: () => void,
|
onMinimize: () => void,
|
||||||
logs: $ReadOnlyArray<LogBoxLog>,
|
logs: $ReadOnlyArray<LogBoxLog>,
|
||||||
selectedIndex: number,
|
selectedIndex: number,
|
||||||
|
hasFatal: boolean,
|
||||||
|}>;
|
|}>;
|
||||||
|
|
||||||
function LogBoxInspector(props: Props): React.Node {
|
function LogBoxInspector(props: Props): React.Node {
|
||||||
|
@ -77,6 +78,7 @@ function LogBoxInspector(props: Props): React.Node {
|
||||||
<LogBoxInspectorFooter
|
<LogBoxInspectorFooter
|
||||||
onDismiss={props.onDismiss}
|
onDismiss={props.onDismiss}
|
||||||
onMinimize={props.onMinimize}
|
onMinimize={props.onMinimize}
|
||||||
|
hasFatal={props.hasFatal}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*
|
*
|
||||||
* @flow strict-local
|
* @flow
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -21,9 +21,18 @@ import * as LogBoxStyle from './LogBoxStyle';
|
||||||
type Props = $ReadOnly<{|
|
type Props = $ReadOnly<{|
|
||||||
onDismiss: () => void,
|
onDismiss: () => void,
|
||||||
onMinimize: () => void,
|
onMinimize: () => void,
|
||||||
|
hasFatal: boolean,
|
||||||
|}>;
|
|}>;
|
||||||
|
|
||||||
function LogBoxInspectorFooter(props: Props): React.Node {
|
function LogBoxInspectorFooter(props: Props): React.Node {
|
||||||
|
if (props.hasFatal) {
|
||||||
|
return (
|
||||||
|
<View style={styles.root}>
|
||||||
|
<FatalButton />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.root}>
|
<View style={styles.root}>
|
||||||
<FooterButton text="Minimize" onPress={props.onMinimize} />
|
<FooterButton text="Minimize" onPress={props.onMinimize} />
|
||||||
|
@ -54,6 +63,55 @@ function FooterButton(props: ButtonProps): React.Node {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FatalButton(): React.Node {
|
||||||
|
return (
|
||||||
|
<LogBoxButton
|
||||||
|
backgroundColor={{
|
||||||
|
default: LogBoxStyle.getFatalColor(),
|
||||||
|
pressed: LogBoxStyle.getFatalDarkColor(),
|
||||||
|
}}
|
||||||
|
onPress={() =>
|
||||||
|
require('../../Utilities/DevSettings').reload('LogBox fatal')
|
||||||
|
}
|
||||||
|
style={fatalStyles.button}>
|
||||||
|
<View style={[fatalStyles.content]}>
|
||||||
|
<Text style={fatalStyles.label}>Reload</Text>
|
||||||
|
<Text style={fatalStyles.subtextLabel}>
|
||||||
|
Fatal errors require a full reload
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<SafeAreaView />
|
||||||
|
</LogBoxButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fatalStyles = StyleSheet.create({
|
||||||
|
button: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
alignItems: 'center',
|
||||||
|
height: 60,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
subtext: {
|
||||||
|
height: 60,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
color: LogBoxStyle.getTextColor(1),
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
includeFontPadding: false,
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
|
subtextLabel: {
|
||||||
|
color: LogBoxStyle.getTextColor(0.8),
|
||||||
|
fontSize: 11,
|
||||||
|
includeFontPadding: false,
|
||||||
|
lineHeight: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const buttonStyles = StyleSheet.create({
|
const buttonStyles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -67,7 +125,7 @@ const buttonStyles = StyleSheet.create({
|
||||||
color: LogBoxStyle.getTextColor(1),
|
color: LogBoxStyle.getTextColor(1),
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
includeFontPadding: false,
|
includeFontPadding: false,
|
||||||
lineHeight: 18,
|
lineHeight: 20,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,22 @@ function LogBoxInspectorHeader(props: Props): React.Node {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const backgroundForLevel = (level: LogLevel) =>
|
||||||
|
({
|
||||||
|
warn: {
|
||||||
|
default: LogBoxStyle.getWarningColor(),
|
||||||
|
pressed: LogBoxStyle.getWarningDarkColor(),
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
default: LogBoxStyle.getErrorColor(),
|
||||||
|
pressed: LogBoxStyle.getErrorDarkColor(),
|
||||||
|
},
|
||||||
|
fatal: {
|
||||||
|
default: LogBoxStyle.getFatalColor(),
|
||||||
|
pressed: LogBoxStyle.getFatalDarkColor(),
|
||||||
|
},
|
||||||
|
}[level]);
|
||||||
|
|
||||||
function LogBoxInspectorHeaderButton(
|
function LogBoxInspectorHeaderButton(
|
||||||
props: $ReadOnly<{|
|
props: $ReadOnly<{|
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
|
@ -69,16 +85,7 @@ function LogBoxInspectorHeaderButton(
|
||||||
): React.Node {
|
): React.Node {
|
||||||
return (
|
return (
|
||||||
<LogBoxButton
|
<LogBoxButton
|
||||||
backgroundColor={{
|
backgroundColor={backgroundForLevel(props.level)}
|
||||||
default:
|
|
||||||
props.level === 'warn'
|
|
||||||
? LogBoxStyle.getWarningColor()
|
|
||||||
: LogBoxStyle.getErrorColor(),
|
|
||||||
pressed:
|
|
||||||
props.level === 'warn'
|
|
||||||
? LogBoxStyle.getWarningDarkColor()
|
|
||||||
: LogBoxStyle.getErrorDarkColor(),
|
|
||||||
}}
|
|
||||||
onPress={props.disabled ? null : props.onPress}
|
onPress={props.disabled ? null : props.onPress}
|
||||||
style={headerStyles.button}>
|
style={headerStyles.button}>
|
||||||
{props.disabled ? null : (
|
{props.disabled ? null : (
|
||||||
|
@ -96,7 +103,7 @@ const headerStyles = StyleSheet.create({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginTop: 3,
|
marginTop: 5,
|
||||||
marginRight: 6,
|
marginRight: 6,
|
||||||
marginLeft: 6,
|
marginLeft: 6,
|
||||||
marginBottom: -8,
|
marginBottom: -8,
|
||||||
|
@ -108,6 +115,9 @@ const headerStyles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
fatal: {
|
||||||
|
backgroundColor: LogBoxStyle.getFatalColor(),
|
||||||
|
},
|
||||||
warn: {
|
warn: {
|
||||||
backgroundColor: LogBoxStyle.getWarningColor(),
|
backgroundColor: LogBoxStyle.getWarningColor(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -51,7 +51,7 @@ function LogBoxInspectorMessageHeader(props: Props): React.Node {
|
||||||
<View style={messageStyles.body}>
|
<View style={messageStyles.body}>
|
||||||
<View style={messageStyles.heading}>
|
<View style={messageStyles.heading}>
|
||||||
<Text style={[messageStyles.headingText, messageStyles[props.level]]}>
|
<Text style={[messageStyles.headingText, messageStyles[props.level]]}>
|
||||||
{props.level === 'warn' ? 'Warning' : 'Error'}
|
{{warn: 'Warning', error: 'Error', fatal: 'Fatal Error'}[props.level]}
|
||||||
</Text>
|
</Text>
|
||||||
{renderShowMore()}
|
{renderShowMore()}
|
||||||
</View>
|
</View>
|
||||||
|
@ -106,6 +106,9 @@ const messageStyles = StyleSheet.create({
|
||||||
error: {
|
error: {
|
||||||
color: LogBoxStyle.getErrorColor(1),
|
color: LogBoxStyle.getErrorColor(1),
|
||||||
},
|
},
|
||||||
|
fatal: {
|
||||||
|
color: LogBoxStyle.getFatalColor(1),
|
||||||
|
},
|
||||||
messageText: {
|
messageText: {
|
||||||
color: LogBoxStyle.getTextColor(0.6),
|
color: LogBoxStyle.getTextColor(0.6),
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,6 +30,14 @@ export function getWarningDarkColor(opacity?: number): string {
|
||||||
return `rgba(224, 167, 8, ${opacity == null ? 1 : opacity})`;
|
return `rgba(224, 167, 8, ${opacity == null ? 1 : opacity})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFatalColor(opacity?: number): string {
|
||||||
|
return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFatalDarkColor(opacity?: number): string {
|
||||||
|
return `rgba(208, 75, 95, ${opacity == null ? 1 : opacity})`;
|
||||||
|
}
|
||||||
|
|
||||||
export function getErrorColor(opacity?: number): string {
|
export function getErrorColor(opacity?: number): string {
|
||||||
return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
|
return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,4 +137,86 @@ describe('LogBoxContainer', () => {
|
||||||
|
|
||||||
expect(output).toMatchSnapshot();
|
expect(output).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render fatal before warn and error', () => {
|
||||||
|
const output = render.shallowRender(
|
||||||
|
<LogBoxContainer
|
||||||
|
onDismiss={() => {}}
|
||||||
|
onDismissWarns={() => {}}
|
||||||
|
onDismissErrors={() => {}}
|
||||||
|
logs={
|
||||||
|
new Set([
|
||||||
|
new LogBoxLog(
|
||||||
|
'fatal',
|
||||||
|
{
|
||||||
|
content: 'Some kind of fatal message',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of fatal message',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
new LogBoxLog(
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
content: 'Some kind of message',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of message',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
new LogBoxLog(
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
content: 'Some kind of message (latest)',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of message (latest)',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render most recent fatal', () => {
|
||||||
|
const output = render.shallowRender(
|
||||||
|
<LogBoxContainer
|
||||||
|
onDismiss={() => {}}
|
||||||
|
onDismissWarns={() => {}}
|
||||||
|
onDismissErrors={() => {}}
|
||||||
|
logs={
|
||||||
|
new Set([
|
||||||
|
new LogBoxLog(
|
||||||
|
'fatal',
|
||||||
|
{
|
||||||
|
content: 'Should not be selected',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of fatal message',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
new LogBoxLog(
|
||||||
|
'fatal',
|
||||||
|
{
|
||||||
|
content: 'Should be selected',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of message',
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,6 +37,16 @@ const logs = [
|
||||||
'Some kind of message (second)',
|
'Some kind of message (second)',
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
|
new LogBoxLog(
|
||||||
|
'fatal',
|
||||||
|
{
|
||||||
|
content: 'Some kind of message (third)',
|
||||||
|
substitutions: [],
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
'Some kind of message (third)',
|
||||||
|
[],
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('LogBoxContainer', () => {
|
describe('LogBoxContainer', () => {
|
||||||
|
@ -48,6 +58,7 @@ describe('LogBoxContainer', () => {
|
||||||
onChangeSelectedIndex={() => {}}
|
onChangeSelectedIndex={() => {}}
|
||||||
logs={[]}
|
logs={[]}
|
||||||
selectedIndex={0}
|
selectedIndex={0}
|
||||||
|
hasFatal={false}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,20 +73,22 @@ describe('LogBoxContainer', () => {
|
||||||
onChangeSelectedIndex={() => {}}
|
onChangeSelectedIndex={() => {}}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
selectedIndex={0}
|
selectedIndex={0}
|
||||||
|
hasFatal={false}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output).toMatchSnapshot();
|
expect(output).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render error with selectedIndex 1', () => {
|
it('should render fatal with selectedIndex 2', () => {
|
||||||
const output = render.shallowRender(
|
const output = render.shallowRender(
|
||||||
<LogBoxInspector
|
<LogBoxInspector
|
||||||
onDismiss={() => {}}
|
onDismiss={() => {}}
|
||||||
onMinimize={() => {}}
|
onMinimize={() => {}}
|
||||||
onChangeSelectedIndex={() => {}}
|
onChangeSelectedIndex={() => {}}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
selectedIndex={1}
|
selectedIndex={2}
|
||||||
|
hasFatal={true}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,23 @@ const render = require('../../../../jest/renderer');
|
||||||
describe('LogBoxInspectorFooter', () => {
|
describe('LogBoxInspectorFooter', () => {
|
||||||
it('should render two buttons', () => {
|
it('should render two buttons', () => {
|
||||||
const output = render.shallowRender(
|
const output = render.shallowRender(
|
||||||
<LogBoxInspectorFooter onMinimize={() => {}} onDismiss={() => {}} />,
|
<LogBoxInspectorFooter
|
||||||
|
onMinimize={() => {}}
|
||||||
|
onDismiss={() => {}}
|
||||||
|
hasFatal={false}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render fatal button', () => {
|
||||||
|
const output = render.shallowRender(
|
||||||
|
<LogBoxInspectorFooter
|
||||||
|
onMinimize={() => {}}
|
||||||
|
onDismiss={() => {}}
|
||||||
|
hasFatal
|
||||||
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output).toMatchSnapshot();
|
expect(output).toMatchSnapshot();
|
||||||
|
|
|
@ -17,13 +17,29 @@ const LogBoxInspectorMessageHeader = require('../LogBoxInspectorMessageHeader')
|
||||||
const render = require('../../../../jest/renderer');
|
const render = require('../../../../jest/renderer');
|
||||||
|
|
||||||
describe('LogBoxInspectorMessageHeader', () => {
|
describe('LogBoxInspectorMessageHeader', () => {
|
||||||
it('should not render error', () => {
|
it('should render error', () => {
|
||||||
const output = render.shallowRender(
|
const output = render.shallowRender(
|
||||||
<LogBoxInspectorMessageHeader
|
<LogBoxInspectorMessageHeader
|
||||||
level="error"
|
level="error"
|
||||||
collapsed={false}
|
collapsed={false}
|
||||||
message={{
|
message={{
|
||||||
content: 'Short',
|
content: 'Some error message',
|
||||||
|
substitutions: [],
|
||||||
|
}}
|
||||||
|
onPress={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render fatal', () => {
|
||||||
|
const output = render.shallowRender(
|
||||||
|
<LogBoxInspectorMessageHeader
|
||||||
|
level="fatal"
|
||||||
|
collapsed={false}
|
||||||
|
message={{
|
||||||
|
content: 'Some fatal message',
|
||||||
substitutions: [],
|
substitutions: [],
|
||||||
}}
|
}}
|
||||||
onPress={() => {}}
|
onPress={() => {}}
|
||||||
|
|
|
@ -91,6 +91,138 @@ exports[`LogBoxContainer should render both an error and warning 1`] = `
|
||||||
</View>
|
</View>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`LogBoxContainer should render fatal before warn and error 1`] = `
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"bottom": 0,
|
||||||
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LogBoxInspector
|
||||||
|
hasFatal={true}
|
||||||
|
logs={
|
||||||
|
Array [
|
||||||
|
LogBoxLog {
|
||||||
|
"category": "Some kind of fatal message",
|
||||||
|
"componentStack": Array [],
|
||||||
|
"count": 1,
|
||||||
|
"level": "fatal",
|
||||||
|
"message": Object {
|
||||||
|
"content": "Some kind of fatal message",
|
||||||
|
"substitutions": Array [],
|
||||||
|
},
|
||||||
|
"stack": Array [],
|
||||||
|
"symbolicated": Object {
|
||||||
|
"error": null,
|
||||||
|
"stack": null,
|
||||||
|
"status": "NONE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogBoxLog {
|
||||||
|
"category": "Some kind of message",
|
||||||
|
"componentStack": Array [],
|
||||||
|
"count": 1,
|
||||||
|
"level": "warn",
|
||||||
|
"message": Object {
|
||||||
|
"content": "Some kind of message",
|
||||||
|
"substitutions": Array [],
|
||||||
|
},
|
||||||
|
"stack": Array [],
|
||||||
|
"symbolicated": Object {
|
||||||
|
"error": null,
|
||||||
|
"stack": null,
|
||||||
|
"status": "NONE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogBoxLog {
|
||||||
|
"category": "Some kind of message (latest)",
|
||||||
|
"componentStack": Array [],
|
||||||
|
"count": 1,
|
||||||
|
"level": "error",
|
||||||
|
"message": Object {
|
||||||
|
"content": "Some kind of message (latest)",
|
||||||
|
"substitutions": Array [],
|
||||||
|
},
|
||||||
|
"stack": Array [],
|
||||||
|
"symbolicated": Object {
|
||||||
|
"error": null,
|
||||||
|
"stack": null,
|
||||||
|
"status": "NONE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
onChangeSelectedIndex={[Function]}
|
||||||
|
onDismiss={[Function]}
|
||||||
|
onMinimize={[Function]}
|
||||||
|
selectedIndex={0}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`LogBoxContainer should render most recent fatal 1`] = `
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"bottom": 0,
|
||||||
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LogBoxInspector
|
||||||
|
hasFatal={true}
|
||||||
|
logs={
|
||||||
|
Array [
|
||||||
|
LogBoxLog {
|
||||||
|
"category": "Some kind of fatal message",
|
||||||
|
"componentStack": Array [],
|
||||||
|
"count": 1,
|
||||||
|
"level": "fatal",
|
||||||
|
"message": Object {
|
||||||
|
"content": "Should not be selected",
|
||||||
|
"substitutions": Array [],
|
||||||
|
},
|
||||||
|
"stack": Array [],
|
||||||
|
"symbolicated": Object {
|
||||||
|
"error": null,
|
||||||
|
"stack": null,
|
||||||
|
"status": "NONE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogBoxLog {
|
||||||
|
"category": "Some kind of message",
|
||||||
|
"componentStack": Array [],
|
||||||
|
"count": 1,
|
||||||
|
"level": "fatal",
|
||||||
|
"message": Object {
|
||||||
|
"content": "Should be selected",
|
||||||
|
"substitutions": Array [],
|
||||||
|
},
|
||||||
|
"stack": Array [],
|
||||||
|
"symbolicated": Object {
|
||||||
|
"error": null,
|
||||||
|
"stack": null,
|
||||||
|
"status": "NONE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
onChangeSelectedIndex={[Function]}
|
||||||
|
onDismiss={[Function]}
|
||||||
|
onMinimize={[Function]}
|
||||||
|
selectedIndex={1}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
|
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
|
||||||
|
|
||||||
exports[`LogBoxContainer should render the latest error 1`] = `
|
exports[`LogBoxContainer should render the latest error 1`] = `
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`LogBoxContainer should render error with selectedIndex 1 1`] = `
|
exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
|
@ -11,20 +11,20 @@ exports[`LogBoxContainer should render error with selectedIndex 1 1`] = `
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<LogBoxInspectorHeader
|
<LogBoxInspectorHeader
|
||||||
level="error"
|
level="fatal"
|
||||||
onSelectIndex={[Function]}
|
onSelectIndex={[Function]}
|
||||||
selectedIndex={1}
|
selectedIndex={2}
|
||||||
total={2}
|
total={3}
|
||||||
/>
|
/>
|
||||||
<LogBoxInspectorBody
|
<LogBoxInspectorBody
|
||||||
log={
|
log={
|
||||||
LogBoxLog {
|
LogBoxLog {
|
||||||
"category": "Some kind of message (second)",
|
"category": "Some kind of message (third)",
|
||||||
"componentStack": Array [],
|
"componentStack": Array [],
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"level": "error",
|
"level": "fatal",
|
||||||
"message": Object {
|
"message": Object {
|
||||||
"content": "Some kind of message (second)",
|
"content": "Some kind of message (third)",
|
||||||
"substitutions": Array [],
|
"substitutions": Array [],
|
||||||
},
|
},
|
||||||
"stack": Array [],
|
"stack": Array [],
|
||||||
|
@ -38,6 +38,7 @@ exports[`LogBoxContainer should render error with selectedIndex 1 1`] = `
|
||||||
onRetry={[Function]}
|
onRetry={[Function]}
|
||||||
/>
|
/>
|
||||||
<LogBoxInspectorFooter
|
<LogBoxInspectorFooter
|
||||||
|
hasFatal={true}
|
||||||
onDismiss={[Function]}
|
onDismiss={[Function]}
|
||||||
onMinimize={[Function]}
|
onMinimize={[Function]}
|
||||||
/>
|
/>
|
||||||
|
@ -60,7 +61,7 @@ exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
|
||||||
level="warn"
|
level="warn"
|
||||||
onSelectIndex={[Function]}
|
onSelectIndex={[Function]}
|
||||||
selectedIndex={0}
|
selectedIndex={0}
|
||||||
total={2}
|
total={3}
|
||||||
/>
|
/>
|
||||||
<LogBoxInspectorBody
|
<LogBoxInspectorBody
|
||||||
log={
|
log={
|
||||||
|
@ -84,6 +85,7 @@ exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
|
||||||
onRetry={[Function]}
|
onRetry={[Function]}
|
||||||
/>
|
/>
|
||||||
<LogBoxInspectorFooter
|
<LogBoxInspectorFooter
|
||||||
|
hasFatal={false}
|
||||||
onDismiss={[Function]}
|
onDismiss={[Function]}
|
||||||
onMinimize={[Function]}
|
onMinimize={[Function]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,26 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`LogBoxInspectorFooter should render fatal button 1`] = `
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "rgba(51, 51, 51, 1)",
|
||||||
|
"elevation": 1,
|
||||||
|
"flexDirection": "row",
|
||||||
|
"shadowColor": "#000",
|
||||||
|
"shadowOffset": Object {
|
||||||
|
"height": -2,
|
||||||
|
"width": 0,
|
||||||
|
},
|
||||||
|
"shadowOpacity": 0.5,
|
||||||
|
"shadowRadius": 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FatalButton />
|
||||||
|
</View>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`LogBoxInspectorFooter should render two buttons 1`] = `
|
exports[`LogBoxInspectorFooter should render two buttons 1`] = `
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
|
|
|
@ -78,84 +78,6 @@ exports[`LogBoxInspectorMessageHeader should not render collapse button for shor
|
||||||
</View>
|
</View>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`LogBoxInspectorMessageHeader should not render error 1`] = `
|
|
||||||
<View
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"backgroundColor": "rgba(51, 51, 51, 1)",
|
|
||||||
"elevation": 2,
|
|
||||||
"flex": 0,
|
|
||||||
"shadowColor": "#000",
|
|
||||||
"shadowOffset": Object {
|
|
||||||
"height": 2,
|
|
||||||
"width": 0,
|
|
||||||
},
|
|
||||||
"shadowOpacity": 0.5,
|
|
||||||
"shadowRadius": 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"alignItems": "center",
|
|
||||||
"flexDirection": "row",
|
|
||||||
"marginBottom": 5,
|
|
||||||
"marginTop": 10,
|
|
||||||
"paddingHorizontal": 12,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"flex": 1,
|
|
||||||
"fontSize": 20,
|
|
||||||
"fontWeight": "600",
|
|
||||||
"includeFontPadding": false,
|
|
||||||
"lineHeight": 28,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"color": "rgba(243, 83, 105, 1)",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Error
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Text
|
|
||||||
numberOfLines={null}
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"color": "rgba(255, 255, 255, 1)",
|
|
||||||
"fontSize": 14,
|
|
||||||
"fontWeight": "500",
|
|
||||||
"includeFontPadding": false,
|
|
||||||
"lineHeight": 20,
|
|
||||||
"paddingBottom": 10,
|
|
||||||
"paddingHorizontal": 12,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<LogBoxMessage
|
|
||||||
message={
|
|
||||||
Object {
|
|
||||||
"content": "Short",
|
|
||||||
"substitutions": Array [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"color": "rgba(255, 255, 255, 0.6)",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`LogBoxInspectorMessageHeader should render "collapse" if expanded 1`] = `
|
exports[`LogBoxInspectorMessageHeader should render "collapse" if expanded 1`] = `
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
|
@ -369,3 +291,159 @@ exports[`LogBoxInspectorMessageHeader should render "see more" if collapsed 1`]
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`LogBoxInspectorMessageHeader should render error 1`] = `
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "rgba(51, 51, 51, 1)",
|
||||||
|
"elevation": 2,
|
||||||
|
"flex": 0,
|
||||||
|
"shadowColor": "#000",
|
||||||
|
"shadowOffset": Object {
|
||||||
|
"height": 2,
|
||||||
|
"width": 0,
|
||||||
|
},
|
||||||
|
"shadowOpacity": 0.5,
|
||||||
|
"shadowRadius": 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"alignItems": "center",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"marginBottom": 5,
|
||||||
|
"marginTop": 10,
|
||||||
|
"paddingHorizontal": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flex": 1,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontWeight": "600",
|
||||||
|
"includeFontPadding": false,
|
||||||
|
"lineHeight": 28,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"color": "rgba(243, 83, 105, 1)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Error
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text
|
||||||
|
numberOfLines={null}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "rgba(255, 255, 255, 1)",
|
||||||
|
"fontSize": 14,
|
||||||
|
"fontWeight": "500",
|
||||||
|
"includeFontPadding": false,
|
||||||
|
"lineHeight": 20,
|
||||||
|
"paddingBottom": 10,
|
||||||
|
"paddingHorizontal": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LogBoxMessage
|
||||||
|
message={
|
||||||
|
Object {
|
||||||
|
"content": "Some error message",
|
||||||
|
"substitutions": Array [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "rgba(255, 255, 255, 0.6)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`LogBoxInspectorMessageHeader should render fatal 1`] = `
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "rgba(51, 51, 51, 1)",
|
||||||
|
"elevation": 2,
|
||||||
|
"flex": 0,
|
||||||
|
"shadowColor": "#000",
|
||||||
|
"shadowOffset": Object {
|
||||||
|
"height": 2,
|
||||||
|
"width": 0,
|
||||||
|
},
|
||||||
|
"shadowOpacity": 0.5,
|
||||||
|
"shadowRadius": 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"alignItems": "center",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"marginBottom": 5,
|
||||||
|
"marginTop": 10,
|
||||||
|
"paddingHorizontal": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flex": 1,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontWeight": "600",
|
||||||
|
"includeFontPadding": false,
|
||||||
|
"lineHeight": 28,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"color": "rgba(243, 83, 105, 1)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Fatal Error
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text
|
||||||
|
numberOfLines={null}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "rgba(255, 255, 255, 1)",
|
||||||
|
"fontSize": 14,
|
||||||
|
"fontWeight": "500",
|
||||||
|
"includeFontPadding": false,
|
||||||
|
"lineHeight": 20,
|
||||||
|
"paddingBottom": 10,
|
||||||
|
"paddingHorizontal": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LogBoxMessage
|
||||||
|
message={
|
||||||
|
Object {
|
||||||
|
"content": "Some fatal message",
|
||||||
|
"substitutions": Array [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "rgba(255, 255, 255, 0.6)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
`;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче