diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 6c068aab0d..cc5e8e4bb0 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -83,7 +83,7 @@ src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js src/renderers/shared/shared/__tests__/ReactComponent-test.js * should throw on invalid render targets -* throws usefully when rendering badly-typed elements +* includes owner name in the error about badly-typed elements src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js * should carry through each of the phases of setup diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index c596a95630..7562b2881b 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1221,6 +1221,7 @@ src/renderers/shared/shared/__tests__/ReactComponent-test.js * should support new-style refs with mixed-up owners * should call refs at the correct time * fires the callback after a component is rendered +* throws usefully when rendering badly-typed elements src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js * should not reuse an instance when it has been unmounted diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js index 9c3604a5f8..3b30d19cde 100644 --- a/src/renderers/shared/fiber/ReactFiber.js +++ b/src/renderers/shared/fiber/ReactFiber.js @@ -41,6 +41,8 @@ var { NoEffect, } = require('ReactTypeOfSideEffect'); +var invariant = require('invariant'); + // A Fiber is work on a Component that needs to be done or was done. There can // be more than one per component. export type Fiber = { @@ -315,7 +317,13 @@ function createFiberFromElementType(type : mixed, key : null | string) : Fiber { // There is probably a clever way to restructure this. fiber = ((type : any) : Fiber); } else { - throw new Error('Unknown component type: ' + typeof type); + invariant( + false, + 'Element type is invalid: expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: %s.', + type == null ? type : typeof type, + // TODO: Stack also includes owner name in the message. + ); } return fiber; } diff --git a/src/renderers/shared/shared/__tests__/ReactComponent-test.js b/src/renderers/shared/shared/__tests__/ReactComponent-test.js index cf73c7230c..e4e63281c3 100644 --- a/src/renderers/shared/shared/__tests__/ReactComponent-test.js +++ b/src/renderers/shared/shared/__tests__/ReactComponent-test.js @@ -347,4 +347,22 @@ describe('ReactComponent', () => { expectDev(console.error.calls.count()).toBe(2); }); + it('includes owner name in the error about badly-typed elements', () => { + spyOn(console, 'error'); + + function Foo() { + var X = undefined; + return ; + } + + expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( + 'Element type is invalid: expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined. ' + + 'Check the render method of `Foo`.' + ); + + // One warning for each element creation + expectDev(console.error.calls.count()).toBe(1); + }); + });