mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
8335ebaeab
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
378 lines
8.9 KiB
JavaScript
378 lines
8.9 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @emails oncall+react_native
|
|
* @format
|
|
* @flow strict-local
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
jest.mock('../../../Core/Devtools/parseErrorStack', () => {
|
|
return {__esModule: true, default: jest.fn(() => [])};
|
|
});
|
|
|
|
const {parseLogBoxLog, parseLogBoxException} = require('../parseLogBoxLog');
|
|
|
|
describe('parseLogBoxLog', () => {
|
|
it('parses strings', () => {
|
|
expect(parseLogBoxLog(['A'])).toEqual({
|
|
componentStack: [],
|
|
category: 'A',
|
|
message: {
|
|
content: 'A',
|
|
substitutions: [],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('parses strings with arguments', () => {
|
|
expect(parseLogBoxLog(['A', 'B', 'C'])).toEqual({
|
|
componentStack: [],
|
|
category: 'A B C',
|
|
message: {
|
|
content: 'A B C',
|
|
substitutions: [],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('parses formatted strings', () => {
|
|
expect(parseLogBoxLog(['%s', 'A'])).toEqual({
|
|
componentStack: [],
|
|
category: '\ufeff%s',
|
|
message: {
|
|
content: 'A',
|
|
substitutions: [
|
|
{
|
|
length: 1,
|
|
offset: 0,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('parses formatted strings with insufficient arguments', () => {
|
|
expect(parseLogBoxLog(['%s %s', 'A'])).toEqual({
|
|
componentStack: [],
|
|
category: '\ufeff%s %s',
|
|
message: {
|
|
content: 'A %s',
|
|
substitutions: [
|
|
{
|
|
length: 1,
|
|
offset: 0,
|
|
},
|
|
{
|
|
length: 2,
|
|
offset: 2,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('parses formatted strings with excess arguments', () => {
|
|
expect(parseLogBoxLog(['%s', 'A', 'B'])).toEqual({
|
|
componentStack: [],
|
|
category: '\ufeff%s B',
|
|
message: {
|
|
content: 'A B',
|
|
substitutions: [
|
|
{
|
|
length: 1,
|
|
offset: 0,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('treats "%s" in arguments as literals', () => {
|
|
expect(parseLogBoxLog(['%s', '%s', 'A'])).toEqual({
|
|
componentStack: [],
|
|
category: '\ufeff%s A',
|
|
message: {
|
|
content: '%s A',
|
|
substitutions: [
|
|
{
|
|
length: 2,
|
|
offset: 0,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('detects a component stack in the second argument', () => {
|
|
expect(
|
|
parseLogBoxLog([
|
|
'Some kind of message',
|
|
'\n in MyComponent (at filename.js:1)\n in MyOtherComponent (at filename2.js:1)',
|
|
]),
|
|
).toEqual({
|
|
componentStack: [
|
|
{component: 'MyComponent', location: 'filename.js:1'},
|
|
{component: 'MyOtherComponent', location: 'filename2.js:1'},
|
|
],
|
|
category: 'Some kind of message',
|
|
message: {
|
|
content: 'Some kind of message',
|
|
substitutions: [],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('detects a component stack in the nth argument', () => {
|
|
expect(
|
|
parseLogBoxLog([
|
|
'Some kind of message',
|
|
'Some other kind of message',
|
|
'\n in MyComponent (at filename.js:1)\n in MyOtherComponent (at filename2.js:1)',
|
|
'Some third kind of message',
|
|
]),
|
|
).toEqual({
|
|
componentStack: [
|
|
{component: 'MyComponent', location: 'filename.js:1'},
|
|
{component: 'MyOtherComponent', location: 'filename2.js:1'},
|
|
],
|
|
category:
|
|
'Some kind of message Some other kind of message Some third kind of message',
|
|
message: {
|
|
content:
|
|
'Some kind of message Some other kind of message Some third kind of message',
|
|
substitutions: [],
|
|
},
|
|
});
|
|
});
|
|
|
|
it('parses a syntax error', () => {
|
|
const error = {
|
|
message: `
|
|
|
|
197 | });
|
|
198 |
|
|
> 199 | export default CrashReactApp;
|
|
| ^
|
|
200 |`,
|
|
originalMessage: `TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)
|
|
|
|
197 | });
|
|
198 |
|
|
> 199 | export default CrashReactApp;
|
|
| ^
|
|
200 |`,
|
|
name: '',
|
|
isComponentError: false,
|
|
componentStack: '',
|
|
stack: [],
|
|
id: 0,
|
|
isFatal: true,
|
|
};
|
|
|
|
expect(parseLogBoxException(error)).toEqual({
|
|
level: 'syntax',
|
|
isComponentError: false,
|
|
codeFrame: {
|
|
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
|
|
location: {row: 199, column: 0},
|
|
content: ` 197 | });
|
|
198 |
|
|
> 199 | export default CrashReactApp;
|
|
| ^
|
|
200 |`,
|
|
},
|
|
message: {
|
|
content: "'import' and 'export' may only appear at the top level",
|
|
substitutions: [],
|
|
},
|
|
stack: [],
|
|
componentStack: [],
|
|
category: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js-199-0',
|
|
});
|
|
});
|
|
|
|
it('parses a error log', () => {
|
|
const error = {
|
|
id: 0,
|
|
isFatal: false,
|
|
isComponentError: false,
|
|
message: '### Error',
|
|
originalMessage: '### Error',
|
|
name: '',
|
|
componentStack:
|
|
'\n in MyComponent (at filename.js:1)\n in MyOtherComponent (at filename2.js:1)',
|
|
stack: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(parseLogBoxException(error)).toEqual({
|
|
level: 'error',
|
|
category: '### Error',
|
|
isComponentError: false,
|
|
message: {
|
|
content: '### Error',
|
|
substitutions: [],
|
|
},
|
|
componentStack: [
|
|
{
|
|
component: 'MyComponent',
|
|
location: 'filename.js:1',
|
|
},
|
|
{
|
|
component: 'MyOtherComponent',
|
|
location: 'filename2.js:1',
|
|
},
|
|
],
|
|
stack: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
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',
|
|
componentStack: null,
|
|
name: '',
|
|
stack: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(parseLogBoxException(error)).toEqual({
|
|
level: 'fatal',
|
|
category: '### Fatal',
|
|
isComponentError: true,
|
|
message: {
|
|
content: '### Fatal',
|
|
substitutions: [],
|
|
},
|
|
componentStack: [],
|
|
stack: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('a malformed syntax error falls back to a fatal', () => {
|
|
const error = {
|
|
id: 0,
|
|
isFatal: true,
|
|
isComponentError: false,
|
|
// Note no code frame.
|
|
message:
|
|
"TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)",
|
|
originalMessage:
|
|
"TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)",
|
|
componentStack: null,
|
|
name: '',
|
|
stack: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(parseLogBoxException(error)).toEqual({
|
|
level: 'fatal',
|
|
category:
|
|
"TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)",
|
|
message: {
|
|
content:
|
|
"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: [
|
|
{
|
|
column: 1,
|
|
file: 'foo.js',
|
|
lineNumber: 1,
|
|
methodName: 'bar',
|
|
collapse: false,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|