Add warning if rendering and HTMLUnknownElement (#9163)
* Add warning if rendering and HTMLUnknownElement * Records fiber tests * Fixes linting and server render tests * Incorporates review comments * Uses ownerDocument instead of document * uses el instead of creating a new element * Removes warning check of voidElementTags * Add missing space to unknown element warning * Only call isCustomComponent once * Spy on console in menuitem test Since menuitem is treated as an unknown element in jsdom it triggers the unknown element warning. * Add unknown element warning to Fiber * Replace instanceof with toString check It is more resilient. * Record tests
Arshabh Kumar Agarwal committed
Apr 14, 2017 at 22:00 UTC
f54fdd544198ba7f76aafb9e5f4e4a8be137ac4c
4 files changed
+74
-14
scripts/fiber/tests-passing.txt
+1
@@ -874,6 +874,7 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
874
* should work error event on <source> element
875
* should not duplicate uppercased selfclosing tags
876
* should warn on upper case HTML tags, not SVG nor custom tags
877
+* should warn if the tag is unrecognized
878
* should warn against children for void elements
879
* should warn against dangerouslySetInnerHTML for void elements
880
* should include owner rather than parent in warnings
src/renderers/dom/fiber/ReactDOMFiberComponent.js
+18
-1
@@ -418,10 +418,13 @@ var ReactDOMFiberComponent = {
418
if (namespaceURI === HTML_NAMESPACE) {
419
namespaceURI = getIntrinsicNamespace(type);
420
}
421
+ if (__DEV__) {
422
+ var isCustomComponentTag = isCustomComponent(type, props);
423
+ }
424
if (namespaceURI === HTML_NAMESPACE) {
425
if (__DEV__) {
426
warning(
424
- type === type.toLowerCase() || isCustomComponent(type, props),
427
+ isCustomComponentTag || type === type.toLowerCase(),
428
'<%s /> is using uppercase HTML. Always use lowercase HTML tags ' +
429
'in React.',
430
type,
@@ -448,6 +451,20 @@ var ReactDOMFiberComponent = {
451
domElement = ownerDocument.createElementNS(namespaceURI, type);
452
}
453
454
+ if (__DEV__) {
455
+ if (namespaceURI === HTML_NAMESPACE) {
456
+ warning(
457
+ isCustomComponentTag ||
458
+ Object.prototype.toString.call(domElement) !==
459
+ '[object HTMLUnknownElement]',
460
+ 'The tag <%s> is unrecognized in this browser. ' +
461
+ 'If you meant to render a React component, start its name with ' +
462
+ 'an uppercase letter.',
463
+ type,
464
+ );
465
+ }
466
+ }
467
+
468
return domElement;
469
},
470
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+28
@@ -809,6 +809,32 @@ describe('ReactDOMComponent', () => {
809
);
810
});
811
812
+ it('should warn if the tag is unrecognized', () => {
813
+ if (ReactDOMFeatureFlags.useCreateElement) {
814
+ spyOn(console, 'error');
815
+
816
+ let realToString;
817
+ try {
818
+ realToString = Object.prototype.toString;
819
+ Object.prototype.toString = function() {
820
+ // Emulate browser behavior which is missing in jsdom
821
+ if (this instanceof window.HTMLUnknownElement) {
822
+ return '[object HTMLUnknownElement]';
823
+ }
824
+ return realToString.apply(this, arguments);
825
+ };
826
+ ReactTestUtils.renderIntoDocument(<mycustomcomponent />);
827
+ } finally {
828
+ Object.prototype.toString = realToString;
829
+ }
830
+
831
+ expectDev(console.error.calls.count()).toBe(1);
832
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
833
+ 'The tag <mycustomcomponent> is unrecognized in this browser',
834
+ );
835
+ }
836
+ });
837
+
838
it('should warn against children for void elements', () => {
839
var container = document.createElement('div');
840
@@ -917,6 +943,8 @@ describe('ReactDOMComponent', () => {
943
});
944
945
it('should treat menuitem as a void element but still create the closing tag', () => {
946
+ // menuitem is not implemented in jsdom, so this triggers the unknown warning error
947
+ spyOn(console, 'error');
948
var container = document.createElement('div');
949
950
var returnedValue = ReactDOMServer.renderToString(
src/renderers/dom/stack/client/ReactDOMComponent.js
+27
-13
@@ -485,6 +485,9 @@ ReactDOMComponent.Mixin = {
485
486
assertValidProps(this, props);
487
488
+ if (__DEV__) {
489
+ var isCustomComponentTag = isCustomComponent(this._tag, props);
490
+ }
491
// We create tags in the namespace of their parent container, except HTML
492
// tags get no namespace.
493
var namespaceURI;
@@ -505,8 +508,7 @@ ReactDOMComponent.Mixin = {
508
if (namespaceURI === DOMNamespaces.html) {
509
if (__DEV__) {
510
warning(
508
- isCustomComponent(this._tag, props) ||
509
- this._tag === this._currentElement.type,
511
+ isCustomComponentTag || this._tag === this._currentElement.type,
512
'<%s /> is using uppercase HTML. Always use lowercase HTML tags ' +
513
'in React.',
514
this._currentElement.type,
@@ -562,17 +564,29 @@ ReactDOMComponent.Mixin = {
564
} else {
565
el = ownerDocument.createElementNS(namespaceURI, type);
566
}
565
- var isCustomComponentTag = isCustomComponent(this._tag, props);
566
- if (__DEV__ && isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) {
567
- var owner = this._currentElement._owner;
568
- var name = (owner && owner.getName()) || 'A component';
569
- warning(
570
- false,
571
- '%s is using shady DOM. Using shady DOM with React can ' +
572
- 'cause things to break subtly.',
573
- name,
574
- );
575
- didWarnShadyDOM = true;
567
+ if (__DEV__) {
568
+ if (isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) {
569
+ var owner = this._currentElement._owner;
570
+ var name = (owner && owner.getName()) || 'A component';
571
+ warning(
572
+ false,
573
+ '%s is using shady DOM. Using shady DOM with React can ' +
574
+ 'cause things to break subtly.',
575
+ name,
576
+ );
577
+ didWarnShadyDOM = true;
578
+ }
579
+ if (this._namespaceURI === DOMNamespaces.html) {
580
+ warning(
581
+ isCustomComponentTag ||
582
+ Object.prototype.toString.call(el) !==
583
+ '[object HTMLUnknownElement]',
584
+ 'The tag <%s> is unrecognized in this browser. ' +
585
+ 'If you meant to render a React component, start its name with ' +
586
+ 'an uppercase letter.',
587
+ this._tag,
588
+ );
589
+ }
590
}
591
ReactDOMComponentTree.precacheNode(this, el);
592
this._flags |= Flags.hasCachedChildNodes;