From 1060ea6e9e40a80262c869d73c8f71d96bc2c379 Mon Sep 17 00:00:00 2001 From: Michel Weststrate Date: Wed, 31 Mar 2021 09:23:32 -0700 Subject: [PATCH] Fix message truncating failing in production builds Summary: Message truncated worked in devs build, but failed in production build, as it JSON formatted React elements in prod build (incorreclty), while it didn't do so in Dev builds, as in dev that generates an exception (undesired) meaning the serialisation gets skipped (desired). Reviewed By: passy, nikoant, priteshrnandgaonkar Differential Revision: D27467280 fbshipit-source-id: 1f8e0ca4750464c778c33b69a8cf13d05f019143 --- .../flipper-plugin/src/ui/DataFormatter.tsx | 14 +- .../src/ui/__tests__/DataFormatter.node.tsx | 178 +++++++++++++++++- 2 files changed, 187 insertions(+), 5 deletions(-) diff --git a/desktop/flipper-plugin/src/ui/DataFormatter.tsx b/desktop/flipper-plugin/src/ui/DataFormatter.tsx index cdddbfa6d..b0f7a7afe 100644 --- a/desktop/flipper-plugin/src/ui/DataFormatter.tsx +++ b/desktop/flipper-plugin/src/ui/DataFormatter.tsx @@ -13,7 +13,7 @@ import { CopyOutlined, } from '@ant-design/icons'; import {Button, Typography} from 'antd'; -import {pad} from 'lodash'; +import {isPlainObject, pad} from 'lodash'; import React, {createElement, Fragment, isValidElement, useState} from 'react'; import {tryGetFlipperLibImplementation} from '../plugin/FlipperLib'; import {safeStringify} from '../utils/safeStringify'; @@ -97,6 +97,9 @@ export const DataFormatter = { }, prettyPrintJson(value: any) { + if (isValidElement(value)) { + return value; + } if (typeof value === 'string' && value.length >= 2) { const last = value.length - 1; // kinda looks like json @@ -112,7 +115,11 @@ export const DataFormatter = { } } } - if (typeof value === 'object' && value !== null) { + if ( + typeof value === 'object' && + value !== null && + (Array.isArray(value) || isPlainObject(value)) + ) { try { // Note: we don't need to be inserted
's in the output, but assume the text container uses // white-space: pre-wrap (or pre) @@ -137,7 +144,8 @@ export const DataFormatter = { }, }; -function TruncateHelper({ +// exported for testing +export function TruncateHelper({ value, maxLength, }: { diff --git a/desktop/flipper-plugin/src/ui/__tests__/DataFormatter.node.tsx b/desktop/flipper-plugin/src/ui/__tests__/DataFormatter.node.tsx index 5f465bd06..b41d7a802 100644 --- a/desktop/flipper-plugin/src/ui/__tests__/DataFormatter.node.tsx +++ b/desktop/flipper-plugin/src/ui/__tests__/DataFormatter.node.tsx @@ -7,7 +7,10 @@ * @format */ -import {DataFormatter} from '../DataFormatter'; +import {render, fireEvent} from '@testing-library/react'; +import React from 'react'; +import {act} from 'react-dom/test-utils'; +import {DataFormatter, TruncateHelper} from '../DataFormatter'; test('default formatter', () => { expect(DataFormatter.format(true)).toMatchInlineSnapshot(`"true"`); @@ -126,7 +129,7 @@ test('linkify formatter', () => { expect(linkify('fb.com')).toMatchInlineSnapshot(`"fb.com"`); }); -test('linkify formatter', () => { +test('jsonify formatter', () => { const jsonify = (value: any) => DataFormatter.format(value, DataFormatter.prettyPrintJson); @@ -162,3 +165,174 @@ test('linkify formatter', () => { `); }); + +test("jsonify doesn't process react elements", () => { + const jsonify = (value: any) => + DataFormatter.format(value, DataFormatter.prettyPrintJson); + + expect(jsonify('abcde')).toEqual('abcde'); + expect(jsonify('{ a: 1 }')).toMatchInlineSnapshot(`"{ a: 1 }"`); + expect(jsonify({a: 1})).toMatchInlineSnapshot(` + "{ + \\"a\\": 1 + }" + `); + expect(jsonify(hi)).toMatchInlineSnapshot(` + + hi + + `); +}); + +test('truncate formatter', () => { + const truncate = (value: any) => + DataFormatter.format(value, DataFormatter.truncate(5)); + + expect(truncate({test: true})).toMatchInlineSnapshot(` + "{ + \\"test\\": true + }" + `); + expect(truncate('abcde')).toEqual('abcde'); + expect(truncate('abcdefghi')).toMatchInlineSnapshot(` + + `); +}); + +test('render truncate helper', () => { + const res = render( + , + ); + expect(res.baseElement).toMatchInlineSnapshot(` + +
+ !! C + + +
+ + `); + act(() => { + fireEvent.click(res.getAllByText(/and \d+ more/)[0]); + }); + expect(res.baseElement).toMatchInlineSnapshot(` + +
+ !! COOL CONTENT !! + + +
+ + `); +});