From d1c25558614164936bb90b6c6dc590106381c446 Mon Sep 17 00:00:00 2001 From: Pavlo Tymchuk Date: Tue, 17 Sep 2019 22:17:04 +0200 Subject: [PATCH] [react-devtools-shared] Added string type check for object name prop in getDisplayName function (#16798) * [react-devtools-shared] Added string type check for object name prop in getDisplayName function from utils.js file; tests included; * Re-added empty string check to getDisplayName() * Tweaked tests to use real functions This more closely simulates how the utility is being used in production, and would catch cases like anonymous functions (with empty string names). --- .../src/__tests__/utils-test.js | 40 +++++++++++++++++++ packages/react-devtools-shared/src/utils.js | 8 ++-- 2 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 packages/react-devtools-shared/src/__tests__/utils-test.js diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js new file mode 100644 index 0000000000000..37e445974a28c --- /dev/null +++ b/packages/react-devtools-shared/src/__tests__/utils-test.js @@ -0,0 +1,40 @@ +/** + * 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. + * + * @flow + */ + +import {getDisplayName} from 'react-devtools-shared/src/utils'; + +describe('utils', () => { + describe('getDisplayName', () => { + it('should return a function name', () => { + function FauxComponent() {} + expect(getDisplayName(FauxComponent)).toEqual('FauxComponent'); + }); + + it('should return a displayName name if specified', () => { + function FauxComponent() {} + FauxComponent.displayName = 'OverrideDisplayName'; + expect(getDisplayName(FauxComponent)).toEqual('OverrideDisplayName'); + }); + + it('should return the fallback for anonymous functions', () => { + expect(getDisplayName(() => {}, 'Fallback')).toEqual('Fallback'); + }); + + it('should return Anonymous for anonymous functions without a fallback', () => { + expect(getDisplayName(() => {})).toEqual('Anonymous'); + }); + + // Simulate a reported bug: + // https://github.com/facebook/react/issues/16685 + it('should return a fallback when the name prop is not a string', () => { + const FauxComponent = {name: {}}; + expect(getDisplayName(FauxComponent, 'Fallback')).toEqual('Fallback'); + }); + }); +}); diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 990ecf996896e..5c22b92100b62 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -46,17 +46,15 @@ export function getDisplayName( return nameFromCache; } - let displayName; + let displayName = fallbackName; // The displayName property is not guaranteed to be a string. // It's only safe to use for our purposes if it's a string. // github.com/facebook/react-devtools/issues/803 if (typeof type.displayName === 'string') { displayName = type.displayName; - } - - if (!displayName) { - displayName = type.name || fallbackName; + } else if (typeof type.name === 'string' && type.name !== '') { + displayName = type.name; } cachedDisplayNames.set(type, displayName);