Clearer ssr error message 11902 (#11966)
* Match error message to one in `ReactFiber.js` * Add undefined/null guard and tests * Update tests and element check * Remove beforeEach block
Jordan Tepper committed
Feb 5, 2018 at 12:09 UTC
86914cb30a7654d13a17d34a3b3a5af97c2d2855
2 files changed
+88
-1
packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
+66
@@ -871,5 +871,71 @@ describe('ReactDOMServerIntegration', () => {
871
: ''),
872
);
873
});
874
+
875
+ describe('badly-typed elements', function() {
876
+ itThrowsWhenRendering(
877
+ 'object',
878
+ async render => {
879
+ let EmptyComponent = {};
880
+ expect(() => {
881
+ EmptyComponent = <EmptyComponent />;
882
+ }).toWarnDev(
883
+ 'Warning: React.createElement: type is invalid -- expected a string ' +
884
+ '(for built-in components) or a class/function (for composite ' +
885
+ 'components) but got: object. You likely forgot to export your ' +
886
+ "component from the file it's defined in, or you might have mixed up " +
887
+ 'default and named imports.',
888
+ );
889
+ await render(EmptyComponent);
890
+ },
891
+ 'Element type is invalid: expected a string (for built-in components) or a class/function ' +
892
+ '(for composite components) but got: object.' +
893
+ (__DEV__
894
+ ? " You likely forgot to export your component from the file it's defined in, " +
895
+ 'or you might have mixed up default and named imports.'
896
+ : ''),
897
+ );
898
+
899
+ itThrowsWhenRendering(
900
+ 'null',
901
+ async render => {
902
+ let NullComponent = null;
903
+ expect(() => {
904
+ NullComponent = <NullComponent />;
905
+ }).toWarnDev(
906
+ 'Warning: React.createElement: type is invalid -- expected a string ' +
907
+ '(for built-in components) or a class/function (for composite ' +
908
+ 'components) but got: null.',
909
+ );
910
+ await render(NullComponent);
911
+ },
912
+ 'Element type is invalid: expected a string (for built-in components) or a class/function ' +
913
+ '(for composite components) but got: null',
914
+ );
915
+
916
+ itThrowsWhenRendering(
917
+ 'undefined',
918
+ async render => {
919
+ let UndefinedComponent = undefined;
920
+ expect(() => {
921
+ UndefinedComponent = <UndefinedComponent />;
922
+ }).toWarnDev(
923
+ 'Warning: React.createElement: type is invalid -- expected a string ' +
924
+ '(for built-in components) or a class/function (for composite ' +
925
+ 'components) but got: undefined. You likely forgot to export your ' +
926
+ "component from the file it's defined in, or you might have mixed up " +
927
+ 'default and named imports.',
928
+ );
929
+
930
+ await render(UndefinedComponent);
931
+ },
932
+ 'Element type is invalid: expected a string (for built-in components) or a class/function ' +
933
+ '(for composite components) but got: undefined.' +
934
+ (__DEV__
935
+ ? " You likely forgot to export your component from the file it's defined in, " +
936
+ 'or you might have mixed up default and named imports.'
937
+ : ''),
938
+ );
939
+ });
940
});
941
});
packages/react-dom/src/server/ReactPartialRenderer.js
+22
-1
@@ -889,12 +889,33 @@ class ReactDOMServerRenderer {
889
break;
890
}
891
}
892
+
893
+ let info = '';
894
+ if (__DEV__) {
895
+ const owner = nextElement._owner;
896
+ if (
897
+ elementType === undefined ||
898
+ (typeof elementType === 'object' &&
899
+ elementType !== null &&
900
+ Object.keys(elementType).length === 0)
901
+ ) {
902
+ info +=
903
+ ' You likely forgot to export your component from the file ' +
904
+ "it's defined in, or you might have mixed up default and " +
905
+ 'named imports.';
906
+ }
907
+ const ownerName = owner ? getComponentName(owner) : null;
908
+ if (ownerName) {
909
+ info += '\n\nCheck the render method of `' + ownerName + '`.';
910
+ }
911
+ }
912
invariant(
913
false,
914
'Element type is invalid: expected a string (for built-in ' +
915
'components) or a class/function (for composite components) ' +
896
- 'but got: %s.',
916
+ 'but got: %s.%s',
917
elementType == null ? elementType : typeof elementType,
918
+ info,
919
);
920
}
921
}