Add support for isRenderError

Summary:
This diff adds `isRenderError` to the Log data, and refactors the LogBoxLog object to accept an object in the constructor instead of adding the 7th argument. No visual updates as those are in the next diff.

Changelog: [Internal]

Reviewed By: cpojer

Differential Revision: D18466192

fbshipit-source-id: e38ef9032b8074abbc7b40cbe7a84d45285944c4
This commit is contained in:
Rick Hanlon
2019-11-13 11:33:38 -08:00
committed by Facebook Github Bot
parent 75deeb32fe
commit 8335ebaeab
12 changed files with 234 additions and 179 deletions
+8 -25
View File
@@ -203,13 +203,14 @@ export function addLog(log: LogData): void {
const stack = parseErrorStack(errorForStackTrace);
appendNewLog(
new LogBoxLog(
log.level,
log.message,
new LogBoxLog({
level: log.level,
message: log.message,
isComponentError: false,
stack,
log.category,
log.componentStack,
),
category: log.category,
componentStack: log.componentStack,
}),
);
} catch (error) {
reportLogBoxError(error);
@@ -222,25 +223,7 @@ export function addException(error: ExtendedExceptionData): void {
// otherwise spammy logs would pause rendering.
setImmediate(() => {
try {
const {
category,
message,
codeFrame,
componentStack,
stack,
level,
} = parseLogBoxException(error);
appendNewLog(
new LogBoxLog(
level,
message,
stack,
category,
componentStack != null ? componentStack : [],
codeFrame,
),
);
appendNewLog(new LogBoxLog(parseLogBoxException(error)));
} catch (loggingError) {
reportLogBoxError(loggingError);
}
+19 -14
View File
@@ -24,6 +24,16 @@ type SymbolicationStatus = 'NONE' | 'PENDING' | 'COMPLETE' | 'FAILED';
export type LogLevel = 'warn' | 'error' | 'fatal' | 'syntax';
export type LogBoxLogData = $ReadOnly<{|
level: LogLevel,
message: Message,
stack: Stack,
category: string,
componentStack: ComponentStack,
codeFrame?: ?CodeFrame,
isComponentError: boolean,
|}>;
export type SymbolicationRequest = $ReadOnly<{|
abort: () => void,
|}>;
@@ -36,6 +46,7 @@ class LogBoxLog {
count: number;
level: LogLevel;
codeFrame: ?CodeFrame;
isComponentError: boolean;
symbolicated:
| $ReadOnly<{|error: null, stack: null, status: 'NONE'|}>
| $ReadOnly<{|error: null, stack: null, status: 'PENDING'|}>
@@ -46,20 +57,14 @@ class LogBoxLog {
status: 'NONE',
};
constructor(
level: LogLevel,
message: Message,
stack: Stack,
category: string,
componentStack: ComponentStack,
codeFrame?: ?CodeFrame,
) {
this.level = level;
this.message = message;
this.stack = stack;
this.category = category;
this.componentStack = componentStack;
this.codeFrame = codeFrame;
constructor(data: LogBoxLogData) {
this.level = data.level;
this.message = data.message;
this.stack = data.stack;
this.category = data.category;
this.componentStack = data.componentStack;
this.codeFrame = data.codeFrame;
this.isComponentError = data.isComponentError;
this.count = 1;
}
@@ -19,18 +19,19 @@ jest.mock('../LogBoxSymbolication', () => {
});
function getLogBoxLog() {
return new (require('../LogBoxLog')).default(
'warn',
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
'Message category...',
[{component: 'LogBoxLog', location: 'LogBoxLog.js:1'}],
{
return new (require('../LogBoxLog')).default({
level: 'warn',
isComponentError: false,
message: {content: '...', substitutions: []},
stack: createStack(['A', 'B', 'C']),
category: 'Message category...',
componentStack: [{component: 'LogBoxLog', location: 'LogBoxLog.js:1'}],
codeFrame: {
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
content: '<code frame>',
},
);
});
}
function getLogBoxSymbolication(): {|
@@ -167,15 +167,16 @@ describe('parseLogBoxLog', () => {
| ^
200 |`,
name: '',
isComponentError: false,
componentStack: '',
stack: [],
id: 0,
isFatal: true,
isComponentError: false,
};
expect(parseLogBoxException(error)).toEqual({
level: 'syntax',
isComponentError: false,
codeFrame: {
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
@@ -190,6 +191,7 @@ describe('parseLogBoxLog', () => {
substitutions: [],
},
stack: [],
componentStack: [],
category: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js-199-0',
});
});
@@ -218,6 +220,7 @@ describe('parseLogBoxLog', () => {
expect(parseLogBoxException(error)).toEqual({
level: 'error',
category: '### Error',
isComponentError: false,
message: {
content: '### Error',
substitutions: [],
@@ -247,7 +250,48 @@ describe('parseLogBoxLog', () => {
it('parses a fatal exception', () => {
const error = {
id: 0,
isFatal: true,
isComponentError: false,
message: '### Fatal',
originalMessage: '### Fatal',
componentStack: null,
name: '',
stack: [
{
column: 1,
file: 'foo.js',
lineNumber: 1,
methodName: 'bar',
collapse: false,
},
],
};
expect(parseLogBoxException(error)).toEqual({
level: 'fatal',
category: '### Fatal',
isComponentError: false,
message: {
content: '### Fatal',
substitutions: [],
},
componentStack: [],
stack: [
{
column: 1,
file: 'foo.js',
lineNumber: 1,
methodName: 'bar',
collapse: false,
},
],
});
});
it('parses a render error', () => {
const error = {
id: 0,
isComponentError: true,
isFatal: true,
message: '### Fatal',
originalMessage: '### Fatal',
@@ -267,6 +311,7 @@ describe('parseLogBoxLog', () => {
expect(parseLogBoxException(error)).toEqual({
level: 'fatal',
category: '### Fatal',
isComponentError: true,
message: {
content: '### Fatal',
substitutions: [],
@@ -316,6 +361,7 @@ describe('parseLogBoxLog', () => {
"TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)",
substitutions: [],
},
isComponentError: false,
componentStack: [],
stack: [
{
+6 -11
View File
@@ -12,9 +12,8 @@
import UTFSequence from '../../UTFSequence';
import stringifySafe from '../../Utilities/stringifySafe';
import type {LogLevel} from './LogBoxLog';
import type {ExceptionData} from '../../Core/NativeExceptionsManager';
import type {Stack} from './LogBoxSymbolication';
import type {LogBoxLogData} from './LogBoxLog';
export type ExtendedExceptionData = ExceptionData & {isComponentError: boolean};
export type Category = string;
@@ -139,14 +138,7 @@ export function parseComponentStack(message: string): ComponentStack {
export function parseLogBoxException(
error: ExtendedExceptionData,
): {|
level: LogLevel,
category: Category,
message: Message,
codeFrame?: CodeFrame,
stack: Stack,
componentStack?: ComponentStack,
|} {
): LogBoxLogData {
const message =
error.originalMessage != null ? error.originalMessage : 'Unknown';
const match = message.match(
@@ -155,8 +147,9 @@ export function parseLogBoxException(
if (!match) {
return {
level: error.isFatal ? 'fatal' : 'error',
level: error.isFatal || error.isComponentError ? 'fatal' : 'error',
stack: error.stack,
isComponentError: error.isComponentError,
componentStack:
error.componentStack != null
? parseComponentStack(error.componentStack)
@@ -169,6 +162,8 @@ export function parseLogBoxException(
return {
level: 'syntax',
stack: [],
isComponentError: false,
componentStack: [],
codeFrame: {
fileName,
location: {
@@ -43,16 +43,17 @@ describe('LogBoxContainer', () => {
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
),
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
])
}
/>,
@@ -71,26 +72,28 @@ describe('LogBoxContainer', () => {
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
),
new LogBoxLog(
'warn',
{
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
[],
'Some kind of message (latest)',
[],
),
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
@@ -109,26 +112,28 @@ describe('LogBoxContainer', () => {
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog(
'error',
{
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
),
new LogBoxLog(
'error',
{
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
[],
'Some kind of message (latest)',
[],
),
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
@@ -147,26 +152,28 @@ describe('LogBoxContainer', () => {
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
),
new LogBoxLog(
'error',
{
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
[],
'Some kind of message (latest)',
[],
),
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
@@ -186,16 +193,17 @@ describe('LogBoxContainer', () => {
selectedLogIndex={0}
logs={
new Set([
new LogBoxLog(
'fatal',
{
new LogBoxLog({
level: 'fatal',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
[],
'Some kind of message',
[],
),
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
])
}
/>,
@@ -215,16 +223,17 @@ describe('LogBoxContainer', () => {
selectedLogIndex={0}
logs={
new Set([
new LogBoxLog(
'syntax',
{
new LogBoxLog({
level: 'syntax',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
[],
'Some kind of syntax error message',
[],
{
stack: [],
category: 'Some kind of syntax error message',
componentStack: [],
codeFrame: {
fileName:
'/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
@@ -234,7 +243,7 @@ describe('LogBoxContainer', () => {
| ^
200 |`,
},
),
}),
])
}
/>,
@@ -17,36 +17,39 @@ const LogBoxLog = require('../../Data/LogBoxLog').default;
const render = require('../../../../jest/renderer');
const logs = [
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (first)',
substitutions: [],
},
[],
'Some kind of message (first)',
[],
),
new LogBoxLog(
'error',
{
stack: [],
category: 'Some kind of message (first)',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (second)',
substitutions: [],
},
[],
'Some kind of message (second)',
[],
),
new LogBoxLog(
'fatal',
{
stack: [],
category: 'Some kind of message (second)',
componentStack: [],
}),
new LogBoxLog({
level: 'fatal',
isComponentError: false,
message: {
content: 'Some kind of message (third)',
substitutions: [],
},
[],
'Some kind of message (third)',
[],
),
stack: [],
category: 'Some kind of message (third)',
componentStack: [],
}),
];
describe('LogBoxContainer', () => {
@@ -22,16 +22,17 @@ describe('LogBoxInspectorReactFrames', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
)
stack: [],
category: 'Some kind of message',
componentStack: [],
})
}
/>,
);
@@ -43,21 +44,22 @@ describe('LogBoxInspectorReactFrames', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
new LogBoxLog(
'warn',
{
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[
stack: [],
category: 'Some kind of message',
componentStack: [
{
component: 'MyComponent',
location: 'MyComponentFile.js:1',
},
],
)
})
}
/>,
);
@@ -17,13 +17,14 @@ const LogBoxInspectorStackFrames = require('../LogBoxInspectorStackFrames')
const LogBoxLog = require('../../Data/LogBoxLog').default;
const render = require('../../../../jest/renderer');
const log = new LogBoxLog(
'warn',
{
const log = new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
[
stack: [
{
column: 1,
file: 'dependency.js',
@@ -39,20 +40,21 @@ const log = new LogBoxLog(
collapse: false,
},
],
'Some kind of message (latest)',
[],
);
category: 'Some kind of message (latest)',
componentStack: [],
});
const logNoStackFrames = new LogBoxLog(
'warn',
{
const logNoStackFrames = new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
[],
'Some kind of message (latest)',
[],
);
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
});
describe('LogBoxInspectorStackFrame', () => {
it('should render stack frames with 1 frame collapsed', () => {
@@ -16,16 +16,17 @@ const LogBoxLogNotification = require('../LogBoxLogNotification').default;
const LogBoxLog = require('../../Data/LogBoxLog').default;
const render = require('../../../../jest/renderer');
const log = new LogBoxLog(
'warn',
{
const log = new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
[],
'Some kind of message',
[],
);
stack: [],
category: 'Some kind of message',
componentStack: [],
});
describe('LogBoxLogNotification', () => {
it('should render log', () => {
@@ -28,6 +28,7 @@ exports[`LogBoxContainer should render both an error and warning notification 1`
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "warn",
"message": Object {
"content": "Some kind of message",
@@ -63,6 +64,7 @@ exports[`LogBoxContainer should render both an error and warning notification 1`
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "error",
"message": Object {
"content": "Some kind of message (latest)",
@@ -115,6 +117,7 @@ exports[`LogBoxContainer should render selected fatal error even when disabled 1
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "fatal",
"message": Object {
"content": "Should be selected",
@@ -168,6 +171,7 @@ exports[`LogBoxContainer should render selected syntax error even when disabled
},
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "syntax",
"message": Object {
"content": "Should be selected",
@@ -218,6 +222,7 @@ exports[`LogBoxContainer should render the latest error notification 1`] = `
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "error",
"message": Object {
"content": "Some kind of message (latest)",
@@ -274,6 +279,7 @@ exports[`LogBoxContainer should render the latest warning notification 1`] = `
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "warn",
"message": Object {
"content": "Some kind of message (latest)",
@@ -23,6 +23,7 @@ exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "fatal",
"message": Object {
"content": "Some kind of message (third)",
@@ -71,6 +72,7 @@ exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "warn",
"message": Object {
"content": "Some kind of message (first)",