@samitouri / QOS-React-2 / commits / f54fdd5441

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;