diff --git a/scripts/fiber/tests-passing-except-dev.txt b/scripts/fiber/tests-passing-except-dev.txt index b013acf875c..e95c7f7c774 100644 --- a/scripts/fiber/tests-passing-except-dev.txt +++ b/scripts/fiber/tests-passing-except-dev.txt @@ -3,152 +3,3 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js * gives source code refs for unknown prop warning for exact elements (ssr) * gives source code refs for unknown prop warning for exact elements in composition (ssr) * should suggest property name if available (ssr) - -src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js -* renders a blank div with client render on top of bad server markup -* renders a div with inline styles with client render on top of bad server markup -* renders a self-closing tag with client render on top of bad server markup -* renders a self-closing tag as a child with client render on top of bad server markup -* renders simple numbers with client render on top of bad server markup -* renders simple strings with client render on top of bad server markup -* renders string prop with true value with client render on top of bad server markup -* renders string prop with false value with client render on top of bad server markup -* renders boolean prop with true value with client render on top of bad server markup -* renders boolean prop with false value with client render on top of bad server markup -* renders boolean prop with self value with client render on top of bad server markup -* renders boolean prop with "" value with client render on top of bad server markup -* renders boolean prop with string value with client render on top of bad server markup -* renders boolean prop with array value with client render on top of bad server markup -* renders boolean prop with object value with client render on top of bad server markup -* renders boolean prop with non-zero number value with client render on top of bad server markup -* renders boolean prop with zero value with client render on top of bad server markup -* renders download prop with true value with client render on top of bad server markup -* renders download prop with false value with client render on top of bad server markup -* renders download prop with string value with client render on top of bad server markup -* renders download prop with string "true" value with client render on top of bad server markup -* renders className prop with string value with client render on top of bad server markup -* renders className prop with empty string value with client render on top of bad server markup -* renders className prop with true value with client render on top of bad server markup -* renders className prop with false value with client render on top of bad server markup -* renders htmlFor with string value with client render on top of bad server markup -* renders htmlFor with an empty string with client render on top of bad server markup -* renders className prop with true value with client render on top of bad server markup -* renders className prop with false value with client render on top of bad server markup -* renders no ref attribute with client render on top of bad server markup -* renders no children attribute with client render on top of bad server markup -* renders no key attribute with client render on top of bad server markup -* renders no dangerouslySetInnerHTML attribute with client render on top of bad server markup -* renders no unknown attributes with client render on top of bad server markup -* renders unknown data- attributes with client render on top of bad server markup -* renders no unknown attributes for non-standard elements with client render on top of bad server markup -* renders unknown attributes for custom elements with client render on top of bad server markup -* renders unknown attributes for custom elements using is with client render on top of bad server markup -* renders no HTML events with client render on top of bad server markup -* renders a div with text with client render on top of bad server markup -* renders a div with text with flanking whitespace with client render on top of bad server markup -* renders a div with an empty text child with client render on top of bad server markup -* renders a div with multiple empty text children with client render on top of bad server markup -* renders a div with multiple whitespace children with client render on top of bad server markup -* renders a div with text sibling to a node with client render on top of bad server markup -* renders a non-standard element with text with client render on top of bad server markup -* renders a custom element with text with client render on top of bad server markup -* renders a leading blank child with a text sibling with client render on top of bad server markup -* renders a trailing blank child with a text sibling with client render on top of bad server markup -* renders an element with two text children with client render on top of bad server markup -* renders a number as single child with client render on top of bad server markup -* renders zero as single child with client render on top of bad server markup -* renders an element with number and text children with client render on top of bad server markup -* renders null single child as blank with client render on top of bad server markup -* renders false single child as blank with client render on top of bad server markup -* renders undefined single child as blank with client render on top of bad server markup -* renders a null component children as empty with client render on top of bad server markup -* renders null children as blank with client render on top of bad server markup -* renders false children as blank with client render on top of bad server markup -* renders null and false children together as blank with client render on top of bad server markup -* renders only null and false children as blank with client render on top of bad server markup -* renders an svg element with client render on top of bad server markup -* renders svg element with an xlink with client render on top of bad server markup -* renders a math element with client render on top of bad server markup -* renders an img with client render on top of bad server markup -* renders a button with client render on top of bad server markup -* renders a div with dangerouslySetInnerHTML with client render on top of bad server markup -* renders a newline-eating tag with content not starting with \n with client render on top of bad server markup -* renders a newline-eating tag with content starting with \n with client render on top of bad server markup -* renders a normal tag with content starting with \n with client render on top of bad server markup -* renders stateless components with client render on top of bad server markup -* renders ES6 class components with client render on top of bad server markup -* renders factory components with client render on top of bad server markup -* renders single child hierarchies of components with client render on top of bad server markup -* renders multi-child hierarchies of components with client render on top of bad server markup -* renders a div with a child with client render on top of bad server markup -* renders a div with multiple children with client render on top of bad server markup -* renders a div with multiple children separated by whitespace with client render on top of bad server markup -* renders a div with a single child surrounded by whitespace with client render on top of bad server markup -* renders >,<, and & as single child with client render on top of bad server markup -* renders >,<, and & as multiple children with client render on top of bad server markup -* renders an input with a value and an onChange with client render on top of bad server markup -* renders an input with a value and readOnly with client render on top of bad server markup -* renders an input with a value and no onChange/readOnly with client render on top of bad server markup -* renders an input with a defaultValue with client render on top of bad server markup -* renders an input value overriding defaultValue with client render on top of bad server markup -* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup -* renders a checkbox that is checked with an onChange with client render on top of bad server markup -* renders a checkbox that is checked with readOnly with client render on top of bad server markup -* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup -* renders a checkbox with defaultChecked with client render on top of bad server markup -* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup -* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup -* renders a textarea with a value and an onChange with client render on top of bad server markup -* renders a textarea with a value and readOnly with client render on top of bad server markup -* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup -* renders a textarea with a defaultValue with client render on top of bad server markup -* renders a textarea value overriding defaultValue with client render on top of bad server markup -* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup -* renders a select with a value and an onChange with client render on top of bad server markup -* renders a select with a value and readOnly with client render on top of bad server markup -* renders a select with a multiple values and an onChange with client render on top of bad server markup -* renders a select with a multiple values and readOnly with client render on top of bad server markup -* renders a select with a value and no onChange/readOnly with client render on top of bad server markup -* renders a select with a defaultValue with client render on top of bad server markup -* renders a select value overriding defaultValue with client render on top of bad server markup -* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup -* renders a controlled text input with client render on top of bad server markup -* renders a controlled textarea with client render on top of bad server markup -* renders a controlled checkbox with client render on top of bad server markup -* renders a controlled select with client render on top of bad server markup -* renders class child with context with client render on top of bad server markup -* renders stateless child with context with client render on top of bad server markup -* renders class child without context with client render on top of bad server markup -* renders stateless child without context with client render on top of bad server markup -* renders class child with wrong context with client render on top of bad server markup -* renders stateless child with wrong context with client render on top of bad server markup -* renders with context passed through to a grandchild with client render on top of bad server markup -* renders a child context overriding a parent context with client render on top of bad server markup -* renders a child context merged with a parent context with client render on top of bad server markup -* renders with a call to componentWillMount before getChildContext with client render on top of bad server markup -* should error reconnecting different element types -* should error reconnecting missing attributes -* should error reconnecting added attributes -* should error reconnecting different attribute values -* should error reconnecting different text -* should error reconnecting different numbers -* should error reconnecting different number from text -* should error reconnecting different text in two code blocks -* should error reconnecting missing children -* should error reconnecting added children -* should error reconnecting more children -* should error reconnecting fewer children -* should error reconnecting reordered children -* should error reconnecting a div with children separated by whitespace on the client -* should error reconnecting a div with children separated by different whitespace on the server -* should error reconnecting a div with children separated by different whitespace -* can distinguish an empty component from a dom node -* can distinguish an empty component from an empty text component -* should error reconnecting a div with different dangerouslySetInnerHTML - -src/renderers/dom/shared/__tests__/ReactMount-test.js -* should warn if mounting into dirty rendered markup -* should account for escaping on a checksum mismatch - -src/renderers/dom/shared/__tests__/ReactServerRendering-test.js -* should have the correct mounting behavior diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 2e36948c29a..16f65a76cef 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -885,326 +885,407 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders a blank div with server stream render * renders a blank div with clean client render * renders a blank div with client render on top of good server markup +* renders a blank div with client render on top of bad server markup * renders a div with inline styles with server string render * renders a div with inline styles with server stream render * renders a div with inline styles with clean client render * renders a div with inline styles with client render on top of good server markup +* renders a div with inline styles with client render on top of bad server markup * renders a self-closing tag with server string render * renders a self-closing tag with server stream render * renders a self-closing tag with clean client render * renders a self-closing tag with client render on top of good server markup +* renders a self-closing tag with client render on top of bad server markup * renders a self-closing tag as a child with server string render * renders a self-closing tag as a child with server stream render * renders a self-closing tag as a child with clean client render * renders a self-closing tag as a child with client render on top of good server markup +* renders a self-closing tag as a child with client render on top of bad server markup * renders simple numbers with server string render * renders simple numbers with server stream render * renders simple numbers with clean client render * renders simple numbers with client render on top of good server markup +* renders simple numbers with client render on top of bad server markup * renders simple strings with server string render * renders simple strings with server stream render * renders simple strings with clean client render * renders simple strings with client render on top of good server markup +* renders simple strings with client render on top of bad server markup * renders string prop with true value with server string render * renders string prop with true value with server stream render * renders string prop with true value with clean client render * renders string prop with true value with client render on top of good server markup +* renders string prop with true value with client render on top of bad server markup * renders string prop with false value with server string render * renders string prop with false value with server stream render * renders string prop with false value with clean client render * renders string prop with false value with client render on top of good server markup +* renders string prop with false value with client render on top of bad server markup * renders boolean prop with true value with server string render * renders boolean prop with true value with server stream render * renders boolean prop with true value with clean client render * renders boolean prop with true value with client render on top of good server markup +* renders boolean prop with true value with client render on top of bad server markup * renders boolean prop with false value with server string render * renders boolean prop with false value with server stream render * renders boolean prop with false value with clean client render * renders boolean prop with false value with client render on top of good server markup +* renders boolean prop with false value with client render on top of bad server markup * renders boolean prop with self value with server string render * renders boolean prop with self value with server stream render * renders boolean prop with self value with clean client render * renders boolean prop with self value with client render on top of good server markup +* renders boolean prop with self value with client render on top of bad server markup * renders boolean prop with "" value with server string render * renders boolean prop with "" value with server stream render * renders boolean prop with "" value with clean client render * renders boolean prop with "" value with client render on top of good server markup +* renders boolean prop with "" value with client render on top of bad server markup * renders boolean prop with string value with server string render * renders boolean prop with string value with server stream render * renders boolean prop with string value with clean client render * renders boolean prop with string value with client render on top of good server markup +* renders boolean prop with string value with client render on top of bad server markup * renders boolean prop with array value with server string render * renders boolean prop with array value with server stream render * renders boolean prop with array value with clean client render * renders boolean prop with array value with client render on top of good server markup +* renders boolean prop with array value with client render on top of bad server markup * renders boolean prop with object value with server string render * renders boolean prop with object value with server stream render * renders boolean prop with object value with clean client render * renders boolean prop with object value with client render on top of good server markup +* renders boolean prop with object value with client render on top of bad server markup * renders boolean prop with non-zero number value with server string render * renders boolean prop with non-zero number value with server stream render * renders boolean prop with non-zero number value with clean client render * renders boolean prop with non-zero number value with client render on top of good server markup +* renders boolean prop with non-zero number value with client render on top of bad server markup * renders boolean prop with zero value with server string render * renders boolean prop with zero value with server stream render * renders boolean prop with zero value with clean client render * renders boolean prop with zero value with client render on top of good server markup +* renders boolean prop with zero value with client render on top of bad server markup * renders download prop with true value with server string render * renders download prop with true value with server stream render * renders download prop with true value with clean client render * renders download prop with true value with client render on top of good server markup +* renders download prop with true value with client render on top of bad server markup * renders download prop with false value with server string render * renders download prop with false value with server stream render * renders download prop with false value with clean client render * renders download prop with false value with client render on top of good server markup +* renders download prop with false value with client render on top of bad server markup * renders download prop with string value with server string render * renders download prop with string value with server stream render * renders download prop with string value with clean client render * renders download prop with string value with client render on top of good server markup +* renders download prop with string value with client render on top of bad server markup * renders download prop with string "true" value with server string render * renders download prop with string "true" value with server stream render * renders download prop with string "true" value with clean client render * renders download prop with string "true" value with client render on top of good server markup +* renders download prop with string "true" value with client render on top of bad server markup * renders className prop with string value with server string render * renders className prop with string value with server stream render * renders className prop with string value with clean client render * renders className prop with string value with client render on top of good server markup +* renders className prop with string value with client render on top of bad server markup * renders className prop with empty string value with server string render * renders className prop with empty string value with server stream render * renders className prop with empty string value with clean client render * renders className prop with empty string value with client render on top of good server markup +* renders className prop with empty string value with client render on top of bad server markup * renders className prop with true value with server string render * renders className prop with true value with server stream render * renders className prop with true value with clean client render * renders className prop with true value with client render on top of good server markup +* renders className prop with true value with client render on top of bad server markup * renders className prop with false value with server string render * renders className prop with false value with server stream render * renders className prop with false value with clean client render * renders className prop with false value with client render on top of good server markup +* renders className prop with false value with client render on top of bad server markup * renders htmlFor with string value with server string render * renders htmlFor with string value with server stream render * renders htmlFor with string value with clean client render * renders htmlFor with string value with client render on top of good server markup +* renders htmlFor with string value with client render on top of bad server markup * renders htmlFor with an empty string with server string render * renders htmlFor with an empty string with server stream render * renders htmlFor with an empty string with clean client render * renders htmlFor with an empty string with client render on top of good server markup +* renders htmlFor with an empty string with client render on top of bad server markup * renders className prop with true value with server string render * renders className prop with true value with server stream render * renders className prop with true value with clean client render * renders className prop with true value with client render on top of good server markup +* renders className prop with true value with client render on top of bad server markup * renders className prop with false value with server string render * renders className prop with false value with server stream render * renders className prop with false value with clean client render * renders className prop with false value with client render on top of good server markup +* renders className prop with false value with client render on top of bad server markup * renders no ref attribute with server string render * renders no ref attribute with server stream render * renders no ref attribute with clean client render * renders no ref attribute with client render on top of good server markup +* renders no ref attribute with client render on top of bad server markup * renders no children attribute with server string render * renders no children attribute with server stream render * renders no children attribute with clean client render * renders no children attribute with client render on top of good server markup +* renders no children attribute with client render on top of bad server markup * renders no key attribute with server string render * renders no key attribute with server stream render * renders no key attribute with clean client render * renders no key attribute with client render on top of good server markup +* renders no key attribute with client render on top of bad server markup * renders no dangerouslySetInnerHTML attribute with server string render * renders no dangerouslySetInnerHTML attribute with server stream render * renders no dangerouslySetInnerHTML attribute with clean client render * renders no dangerouslySetInnerHTML attribute with client render on top of good server markup +* renders no dangerouslySetInnerHTML attribute with client render on top of bad server markup * renders no unknown attributes with server string render * renders no unknown attributes with server stream render * renders no unknown attributes with clean client render * renders no unknown attributes with client render on top of good server markup +* renders no unknown attributes with client render on top of bad server markup * renders unknown data- attributes with server string render * renders unknown data- attributes with server stream render * renders unknown data- attributes with clean client render * renders unknown data- attributes with client render on top of good server markup +* renders unknown data- attributes with client render on top of bad server markup * renders no unknown attributes for non-standard elements with server string render * renders no unknown attributes for non-standard elements with server stream render * renders no unknown attributes for non-standard elements with clean client render * renders no unknown attributes for non-standard elements with client render on top of good server markup +* renders no unknown attributes for non-standard elements with client render on top of bad server markup * renders unknown attributes for custom elements with server string render * renders unknown attributes for custom elements with server stream render * renders unknown attributes for custom elements with clean client render * renders unknown attributes for custom elements with client render on top of good server markup +* renders unknown attributes for custom elements with client render on top of bad server markup * renders unknown attributes for custom elements using is with server string render * renders unknown attributes for custom elements using is with server stream render * renders unknown attributes for custom elements using is with clean client render * renders unknown attributes for custom elements using is with client render on top of good server markup +* renders unknown attributes for custom elements using is with client render on top of bad server markup * renders no HTML events with server string render * renders no HTML events with server stream render * renders no HTML events with clean client render * renders no HTML events with client render on top of good server markup +* renders no HTML events with client render on top of bad server markup * renders a div with text with server string render * renders a div with text with server stream render * renders a div with text with clean client render * renders a div with text with client render on top of good server markup +* renders a div with text with client render on top of bad server markup * renders a div with text with flanking whitespace with server string render * renders a div with text with flanking whitespace with server stream render * renders a div with text with flanking whitespace with clean client render * renders a div with text with flanking whitespace with client render on top of good server markup +* renders a div with text with flanking whitespace with client render on top of bad server markup * renders a div with an empty text child with server string render * renders a div with an empty text child with server stream render * renders a div with an empty text child with clean client render * renders a div with an empty text child with client render on top of good server markup +* renders a div with an empty text child with client render on top of bad server markup * renders a div with multiple empty text children with server string render * renders a div with multiple empty text children with server stream render * renders a div with multiple empty text children with clean client render * renders a div with multiple empty text children with client render on top of good server markup +* renders a div with multiple empty text children with client render on top of bad server markup * renders a div with multiple whitespace children with server string render * renders a div with multiple whitespace children with server stream render * renders a div with multiple whitespace children with clean client render * renders a div with multiple whitespace children with client render on top of good server markup +* renders a div with multiple whitespace children with client render on top of bad server markup * renders a div with text sibling to a node with server string render * renders a div with text sibling to a node with server stream render * renders a div with text sibling to a node with clean client render * renders a div with text sibling to a node with client render on top of good server markup +* renders a div with text sibling to a node with client render on top of bad server markup * renders a non-standard element with text with server string render * renders a non-standard element with text with server stream render * renders a non-standard element with text with clean client render * renders a non-standard element with text with client render on top of good server markup +* renders a non-standard element with text with client render on top of bad server markup * renders a custom element with text with server string render * renders a custom element with text with server stream render * renders a custom element with text with clean client render * renders a custom element with text with client render on top of good server markup +* renders a custom element with text with client render on top of bad server markup * renders a leading blank child with a text sibling with server string render * renders a leading blank child with a text sibling with server stream render * renders a leading blank child with a text sibling with clean client render * renders a leading blank child with a text sibling with client render on top of good server markup +* renders a leading blank child with a text sibling with client render on top of bad server markup * renders a trailing blank child with a text sibling with server string render * renders a trailing blank child with a text sibling with server stream render * renders a trailing blank child with a text sibling with clean client render * renders a trailing blank child with a text sibling with client render on top of good server markup +* renders a trailing blank child with a text sibling with client render on top of bad server markup * renders an element with two text children with server string render * renders an element with two text children with server stream render * renders an element with two text children with clean client render * renders an element with two text children with client render on top of good server markup +* renders an element with two text children with client render on top of bad server markup * renders a number as single child with server string render * renders a number as single child with server stream render * renders a number as single child with clean client render * renders a number as single child with client render on top of good server markup +* renders a number as single child with client render on top of bad server markup * renders zero as single child with server string render * renders zero as single child with server stream render * renders zero as single child with clean client render * renders zero as single child with client render on top of good server markup +* renders zero as single child with client render on top of bad server markup * renders an element with number and text children with server string render * renders an element with number and text children with server stream render * renders an element with number and text children with clean client render * renders an element with number and text children with client render on top of good server markup +* renders an element with number and text children with client render on top of bad server markup * renders null single child as blank with server string render * renders null single child as blank with server stream render * renders null single child as blank with clean client render * renders null single child as blank with client render on top of good server markup +* renders null single child as blank with client render on top of bad server markup * renders false single child as blank with server string render * renders false single child as blank with server stream render * renders false single child as blank with clean client render * renders false single child as blank with client render on top of good server markup +* renders false single child as blank with client render on top of bad server markup * renders undefined single child as blank with server string render * renders undefined single child as blank with server stream render * renders undefined single child as blank with clean client render * renders undefined single child as blank with client render on top of good server markup +* renders undefined single child as blank with client render on top of bad server markup * renders a null component children as empty with server string render * renders a null component children as empty with server stream render * renders a null component children as empty with clean client render * renders a null component children as empty with client render on top of good server markup +* renders a null component children as empty with client render on top of bad server markup * renders null children as blank with server string render * renders null children as blank with server stream render * renders null children as blank with clean client render * renders null children as blank with client render on top of good server markup +* renders null children as blank with client render on top of bad server markup * renders false children as blank with server string render * renders false children as blank with server stream render * renders false children as blank with clean client render * renders false children as blank with client render on top of good server markup +* renders false children as blank with client render on top of bad server markup * renders null and false children together as blank with server string render * renders null and false children together as blank with server stream render * renders null and false children together as blank with clean client render * renders null and false children together as blank with client render on top of good server markup +* renders null and false children together as blank with client render on top of bad server markup * renders only null and false children as blank with server string render * renders only null and false children as blank with server stream render * renders only null and false children as blank with clean client render * renders only null and false children as blank with client render on top of good server markup +* renders only null and false children as blank with client render on top of bad server markup * renders an svg element with server string render * renders an svg element with server stream render * renders an svg element with clean client render * renders an svg element with client render on top of good server markup +* renders an svg element with client render on top of bad server markup * renders svg element with an xlink with server string render * renders svg element with an xlink with server stream render * renders svg element with an xlink with clean client render * renders svg element with an xlink with client render on top of good server markup +* renders svg element with an xlink with client render on top of bad server markup * renders a math element with server string render * renders a math element with server stream render * renders a math element with clean client render * renders a math element with client render on top of good server markup +* renders a math element with client render on top of bad server markup * renders an img with server string render * renders an img with server stream render * renders an img with clean client render * renders an img with client render on top of good server markup +* renders an img with client render on top of bad server markup * renders a button with server string render * renders a button with server stream render * renders a button with clean client render * renders a button with client render on top of good server markup +* renders a button with client render on top of bad server markup * renders a div with dangerouslySetInnerHTML with server string render * renders a div with dangerouslySetInnerHTML with server stream render * renders a div with dangerouslySetInnerHTML with clean client render * renders a div with dangerouslySetInnerHTML with client render on top of good server markup +* renders a div with dangerouslySetInnerHTML with client render on top of bad server markup * renders a newline-eating tag with content not starting with \n with server string render * renders a newline-eating tag with content not starting with \n with server stream render * renders a newline-eating tag with content not starting with \n with clean client render * renders a newline-eating tag with content not starting with \n with client render on top of good server markup +* renders a newline-eating tag with content not starting with \n with client render on top of bad server markup * renders a newline-eating tag with content starting with \n with server string render * renders a newline-eating tag with content starting with \n with server stream render * renders a newline-eating tag with content starting with \n with clean client render * renders a newline-eating tag with content starting with \n with client render on top of good server markup +* renders a newline-eating tag with content starting with \n with client render on top of bad server markup * renders a normal tag with content starting with \n with server string render * renders a normal tag with content starting with \n with server stream render * renders a normal tag with content starting with \n with clean client render * renders a normal tag with content starting with \n with client render on top of good server markup +* renders a normal tag with content starting with \n with client render on top of bad server markup * renders stateless components with server string render * renders stateless components with server stream render * renders stateless components with clean client render * renders stateless components with client render on top of good server markup +* renders stateless components with client render on top of bad server markup * renders ES6 class components with server string render * renders ES6 class components with server stream render * renders ES6 class components with clean client render * renders ES6 class components with client render on top of good server markup +* renders ES6 class components with client render on top of bad server markup * renders factory components with server string render * renders factory components with server stream render * renders factory components with clean client render * renders factory components with client render on top of good server markup +* renders factory components with client render on top of bad server markup * renders single child hierarchies of components with server string render * renders single child hierarchies of components with server stream render * renders single child hierarchies of components with clean client render * renders single child hierarchies of components with client render on top of good server markup +* renders single child hierarchies of components with client render on top of bad server markup * renders multi-child hierarchies of components with server string render * renders multi-child hierarchies of components with server stream render * renders multi-child hierarchies of components with clean client render * renders multi-child hierarchies of components with client render on top of good server markup +* renders multi-child hierarchies of components with client render on top of bad server markup * renders a div with a child with server string render * renders a div with a child with server stream render * renders a div with a child with clean client render * renders a div with a child with client render on top of good server markup +* renders a div with a child with client render on top of bad server markup * renders a div with multiple children with server string render * renders a div with multiple children with server stream render * renders a div with multiple children with clean client render * renders a div with multiple children with client render on top of good server markup +* renders a div with multiple children with client render on top of bad server markup * renders a div with multiple children separated by whitespace with server string render * renders a div with multiple children separated by whitespace with server stream render * renders a div with multiple children separated by whitespace with clean client render * renders a div with multiple children separated by whitespace with client render on top of good server markup +* renders a div with multiple children separated by whitespace with client render on top of bad server markup * renders a div with a single child surrounded by whitespace with server string render * renders a div with a single child surrounded by whitespace with server stream render * renders a div with a single child surrounded by whitespace with clean client render * renders a div with a single child surrounded by whitespace with client render on top of good server markup +* renders a div with a single child surrounded by whitespace with client render on top of bad server markup * renders >,<, and & as single child with server string render * renders >,<, and & as single child with server stream render * renders >,<, and & as single child with clean client render * renders >,<, and & as single child with client render on top of good server markup +* renders >,<, and & as single child with client render on top of bad server markup * renders >,<, and & as multiple children with server string render * renders >,<, and & as multiple children with server stream render * renders >,<, and & as multiple children with clean client render * renders >,<, and & as multiple children with client render on top of good server markup +* renders >,<, and & as multiple children with client render on top of bad server markup * throws when rendering a string component with server string render * throws when rendering a string component with clean client render * throws when rendering a string component with client render on top of bad server markup @@ -1233,114 +1314,144 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders an input with a value and an onChange with server stream render * renders an input with a value and an onChange with clean client render * renders an input with a value and an onChange with client render on top of good server markup +* renders an input with a value and an onChange with client render on top of bad server markup * renders an input with a value and readOnly with server string render * renders an input with a value and readOnly with server stream render * renders an input with a value and readOnly with clean client render * renders an input with a value and readOnly with client render on top of good server markup +* renders an input with a value and readOnly with client render on top of bad server markup * renders an input with a value and no onChange/readOnly with server string render * renders an input with a value and no onChange/readOnly with server stream render * renders an input with a value and no onChange/readOnly with clean client render * renders an input with a value and no onChange/readOnly with client render on top of good server markup +* renders an input with a value and no onChange/readOnly with client render on top of bad server markup * renders an input with a defaultValue with server string render * renders an input with a defaultValue with server stream render * renders an input with a defaultValue with clean client render * renders an input with a defaultValue with client render on top of good server markup +* renders an input with a defaultValue with client render on top of bad server markup * renders an input value overriding defaultValue with server string render * renders an input value overriding defaultValue with server stream render * renders an input value overriding defaultValue with clean client render * renders an input value overriding defaultValue with client render on top of good server markup +* renders an input value overriding defaultValue with client render on top of bad server markup * renders an input value overriding defaultValue no matter the prop order with server string render * renders an input value overriding defaultValue no matter the prop order with server stream render * renders an input value overriding defaultValue no matter the prop order with clean client render * renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup +* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup * renders a checkbox that is checked with an onChange with server string render * renders a checkbox that is checked with an onChange with server stream render * renders a checkbox that is checked with an onChange with clean client render * renders a checkbox that is checked with an onChange with client render on top of good server markup +* renders a checkbox that is checked with an onChange with client render on top of bad server markup * renders a checkbox that is checked with readOnly with server string render * renders a checkbox that is checked with readOnly with server stream render * renders a checkbox that is checked with readOnly with clean client render * renders a checkbox that is checked with readOnly with client render on top of good server markup +* renders a checkbox that is checked with readOnly with client render on top of bad server markup * renders a checkbox that is checked and no onChange/readOnly with server string render * renders a checkbox that is checked and no onChange/readOnly with server stream render * renders a checkbox that is checked and no onChange/readOnly with clean client render * renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup +* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup * renders a checkbox with defaultChecked with server string render * renders a checkbox with defaultChecked with server stream render * renders a checkbox with defaultChecked with clean client render * renders a checkbox with defaultChecked with client render on top of good server markup +* renders a checkbox with defaultChecked with client render on top of bad server markup * renders a checkbox checked overriding defaultChecked with server string render * renders a checkbox checked overriding defaultChecked with server stream render * renders a checkbox checked overriding defaultChecked with clean client render * renders a checkbox checked overriding defaultChecked with client render on top of good server markup +* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup * renders a checkbox checked overriding defaultChecked no matter the prop order with server string render * renders a checkbox checked overriding defaultChecked no matter the prop order with server stream render * renders a checkbox checked overriding defaultChecked no matter the prop order with clean client render * renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup +* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup * renders a textarea with a value and an onChange with server string render * renders a textarea with a value and an onChange with server stream render * renders a textarea with a value and an onChange with clean client render * renders a textarea with a value and an onChange with client render on top of good server markup +* renders a textarea with a value and an onChange with client render on top of bad server markup * renders a textarea with a value and readOnly with server string render * renders a textarea with a value and readOnly with server stream render * renders a textarea with a value and readOnly with clean client render * renders a textarea with a value and readOnly with client render on top of good server markup +* renders a textarea with a value and readOnly with client render on top of bad server markup * renders a textarea with a value and no onChange/readOnly with server string render * renders a textarea with a value and no onChange/readOnly with server stream render * renders a textarea with a value and no onChange/readOnly with clean client render * renders a textarea with a value and no onChange/readOnly with client render on top of good server markup +* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup * renders a textarea with a defaultValue with server string render * renders a textarea with a defaultValue with server stream render * renders a textarea with a defaultValue with clean client render * renders a textarea with a defaultValue with client render on top of good server markup +* renders a textarea with a defaultValue with client render on top of bad server markup * renders a textarea value overriding defaultValue with server string render * renders a textarea value overriding defaultValue with server stream render * renders a textarea value overriding defaultValue with clean client render * renders a textarea value overriding defaultValue with client render on top of good server markup +* renders a textarea value overriding defaultValue with client render on top of bad server markup * renders a textarea value overriding defaultValue no matter the prop order with server string render * renders a textarea value overriding defaultValue no matter the prop order with server stream render * renders a textarea value overriding defaultValue no matter the prop order with clean client render * renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup +* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup * renders a select with a value and an onChange with server string render * renders a select with a value and an onChange with server stream render * renders a select with a value and an onChange with clean client render * renders a select with a value and an onChange with client render on top of good server markup +* renders a select with a value and an onChange with client render on top of bad server markup * renders a select with a value and readOnly with server string render * renders a select with a value and readOnly with server stream render * renders a select with a value and readOnly with clean client render * renders a select with a value and readOnly with client render on top of good server markup +* renders a select with a value and readOnly with client render on top of bad server markup * renders a select with a multiple values and an onChange with server string render * renders a select with a multiple values and an onChange with server stream render * renders a select with a multiple values and an onChange with clean client render * renders a select with a multiple values and an onChange with client render on top of good server markup +* renders a select with a multiple values and an onChange with client render on top of bad server markup * renders a select with a multiple values and readOnly with server string render * renders a select with a multiple values and readOnly with server stream render * renders a select with a multiple values and readOnly with clean client render * renders a select with a multiple values and readOnly with client render on top of good server markup +* renders a select with a multiple values and readOnly with client render on top of bad server markup * renders a select with a value and no onChange/readOnly with server string render * renders a select with a value and no onChange/readOnly with server stream render * renders a select with a value and no onChange/readOnly with clean client render * renders a select with a value and no onChange/readOnly with client render on top of good server markup +* renders a select with a value and no onChange/readOnly with client render on top of bad server markup * renders a select with a defaultValue with server string render * renders a select with a defaultValue with server stream render * renders a select with a defaultValue with clean client render * renders a select with a defaultValue with client render on top of good server markup +* renders a select with a defaultValue with client render on top of bad server markup * renders a select value overriding defaultValue with server string render * renders a select value overriding defaultValue with server stream render * renders a select value overriding defaultValue with clean client render * renders a select value overriding defaultValue with client render on top of good server markup +* renders a select value overriding defaultValue with client render on top of bad server markup * renders a select value overriding defaultValue no matter the prop order with server string render * renders a select value overriding defaultValue no matter the prop order with server stream render * renders a select value overriding defaultValue no matter the prop order with clean client render * renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup +* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup * renders a controlled text input with clean client render * renders a controlled text input with client render on top of good server markup +* renders a controlled text input with client render on top of bad server markup * renders a controlled textarea with clean client render * renders a controlled textarea with client render on top of good server markup +* renders a controlled textarea with client render on top of bad server markup * renders a controlled checkbox with clean client render * renders a controlled checkbox with client render on top of good server markup +* renders a controlled checkbox with client render on top of bad server markup * renders a controlled select with clean client render * renders a controlled select with client render on top of good server markup +* renders a controlled select with client render on top of bad server markup * should not blow away user-entered text on successful reconnect to an uncontrolled input * should not blow away user-entered text on successful reconnect to a controlled input * should not blow away user-entered text on successful reconnect to an uncontrolled checkbox @@ -1351,42 +1462,52 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders class child with context with server stream render * renders class child with context with clean client render * renders class child with context with client render on top of good server markup +* renders class child with context with client render on top of bad server markup * renders stateless child with context with server string render * renders stateless child with context with server stream render * renders stateless child with context with clean client render * renders stateless child with context with client render on top of good server markup +* renders stateless child with context with client render on top of bad server markup * renders class child without context with server string render * renders class child without context with server stream render * renders class child without context with clean client render * renders class child without context with client render on top of good server markup +* renders class child without context with client render on top of bad server markup * renders stateless child without context with server string render * renders stateless child without context with server stream render * renders stateless child without context with clean client render * renders stateless child without context with client render on top of good server markup +* renders stateless child without context with client render on top of bad server markup * renders class child with wrong context with server string render * renders class child with wrong context with server stream render * renders class child with wrong context with clean client render * renders class child with wrong context with client render on top of good server markup +* renders class child with wrong context with client render on top of bad server markup * renders stateless child with wrong context with server string render * renders stateless child with wrong context with server stream render * renders stateless child with wrong context with clean client render * renders stateless child with wrong context with client render on top of good server markup +* renders stateless child with wrong context with client render on top of bad server markup * renders with context passed through to a grandchild with server string render * renders with context passed through to a grandchild with server stream render * renders with context passed through to a grandchild with clean client render * renders with context passed through to a grandchild with client render on top of good server markup +* renders with context passed through to a grandchild with client render on top of bad server markup * renders a child context overriding a parent context with server string render * renders a child context overriding a parent context with server stream render * renders a child context overriding a parent context with clean client render * renders a child context overriding a parent context with client render on top of good server markup +* renders a child context overriding a parent context with client render on top of bad server markup * renders a child context merged with a parent context with server string render * renders a child context merged with a parent context with server stream render * renders a child context merged with a parent context with clean client render * renders a child context merged with a parent context with client render on top of good server markup +* renders a child context merged with a parent context with client render on top of bad server markup * renders with a call to componentWillMount before getChildContext with server string render * renders with a call to componentWillMount before getChildContext with server stream render * renders with a call to componentWillMount before getChildContext with clean client render * renders with a call to componentWillMount before getChildContext with client render on top of good server markup +* renders with a call to componentWillMount before getChildContext with client render on top of bad server markup * throws when rendering if getChildContext exists without childContextTypes with server string render * throws when rendering if getChildContext exists without childContextTypes with clean client render * throws when rendering if getChildContext exists without childContextTypes with client render on top of bad server markup @@ -1406,7 +1527,26 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * should reconnect ES6 Class to Bare Element * should reconnect Pure Component to Bare Element * should reconnect Bare Element to Bare Element +* should error reconnecting different element types +* should error reconnecting missing attributes +* should error reconnecting added attributes +* should error reconnecting different attribute values +* should error reconnecting different text * should reconnect a div with a number and string version of number +* should error reconnecting different numbers +* should error reconnecting different number from text +* should error reconnecting different text in two code blocks +* should error reconnecting missing children +* should error reconnecting added children +* should error reconnecting more children +* should error reconnecting fewer children +* should error reconnecting reordered children +* should error reconnecting a div with children separated by whitespace on the client +* should error reconnecting a div with children separated by different whitespace on the server +* should error reconnecting a div with children separated by different whitespace +* can distinguish an empty component from a dom node +* can distinguish an empty component from an empty text component +* should error reconnecting a div with different dangerouslySetInnerHTML src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js * updates a mounted text component in place @@ -1427,8 +1567,10 @@ src/renderers/dom/shared/__tests__/ReactMount-test.js * should render different components in same root * should unmount and remount if the key changes * should reuse markup if rendering to the same target twice +* should warn if mounting into dirty rendered markup * should not warn if mounting into non-empty node * should warn when mounting into document.body +* should account for escaping on a checksum mismatch * should warn if render removes React-rendered children * should warn if the unmounted node was rendered by another copy of React * passes the correct callback context @@ -1457,6 +1599,7 @@ src/renderers/dom/shared/__tests__/ReactServerRendering-test.js * should generate comment markup for component returns null * should render composite components * should only execute certain lifecycle methods +* should have the correct mounting behavior * should throw with silly args * should not put checksum and React ID on components * should not put checksum and React ID on text components diff --git a/src/renderers/dom/fiber/ReactDOMFiberComponent.js b/src/renderers/dom/fiber/ReactDOMFiberComponent.js index 64026422841..46f91e986d0 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberComponent.js +++ b/src/renderers/dom/fiber/ReactDOMFiberComponent.js @@ -46,6 +46,7 @@ if (__DEV__) { } = ReactDOMUnknownPropertyHook; } +var didWarnInvalidHydration = false; var didWarnShadyDOM = false; var listenTo = ReactBrowserEventEmitter.listenTo; @@ -69,6 +70,66 @@ if (__DEV__) { validateInputPropertes(type, props); validateUnknownPropertes(type, props); }; + + var warnForTextDifference = function(serverText: string, clientText: string) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Text content did not match. Server: "%s" Client: "%s"', + serverText, + clientText, + ); + }; + + var warnForPropDifference = function( + propName: string, + serverValue: mixed, + clientValue: mixed, + ) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Prop `%s` did not match. Server: %s Client: %s', + propName, + JSON.stringify(serverValue), + JSON.stringify(clientValue), + ); + }; + + var warnForExtraAttributes = function(attributeNames: Set) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + var names = []; + attributeNames.forEach(function(name) { + names.push(name); + }); + warning(false, 'Extra attributes from the server: %s', names); + }; + + var testDocument; + // Parse the HTML and read it back to normalize the HTML string so that it + // can be used for comparison. + var normalizeHTML = function(parent: Element, html: string) { + if (!testDocument) { + testDocument = document.implementation.createHTMLDocument(); + } + var testElement = parent.namespaceURI === HTML_NAMESPACE + ? testDocument.createElement(parent.tagName) + : testDocument.createElementNS( + (parent.namespaceURI: any), + parent.tagName, + ); + testElement.innerHTML = html; + return testElement.innerHTML; + }; } function ensureListeningTo(rootContainerElement, registrationName) { @@ -766,6 +827,36 @@ var ReactDOMFiberComponent = { assertValidProps(tag, rawProps, getCurrentFiberOwnerName); + if (__DEV__) { + var extraAttributeNames: Set = new Set(); + var attributes = domElement.attributes; + for (var i = 0; i < attributes.length; i++) { + // TODO: Do we need to lower case this to get case insensitive matches? + var name = attributes[i].name; + switch (name) { + // Built-in attributes are whitelisted + // TODO: Once these are gone from the server renderer, we don't need + // this whitelist aynymore. + case 'data-reactroot': + break; + case 'data-reactid': + break; + case 'data-react-checksum': + break; + // Controlled attributes are not validated + // TODO: Only ignore them on controlled tags. + case 'value': + break; + case 'checked': + break; + case 'selected': + break; + default: + extraAttributeNames.add(attributes[i].name); + } + } + } + var updatePayload = null; for (var propKey in rawProps) { if (!rawProps.hasOwnProperty(propKey)) { @@ -784,10 +875,16 @@ var ReactDOMFiberComponent = { // TODO: Should we use domElement.firstChild.nodeValue to compare? if (typeof nextProp === 'string') { if (domElement.textContent !== nextProp) { + if (__DEV__) { + warnForTextDifference(domElement.textContent, nextProp); + } updatePayload = [CHILDREN, nextProp]; } } else if (typeof nextProp === 'number') { if (domElement.textContent !== '' + nextProp) { + if (__DEV__) { + warnForTextDifference(domElement.textContent, nextProp); + } updatePayload = [CHILDREN, '' + nextProp]; } } @@ -795,6 +892,64 @@ var ReactDOMFiberComponent = { if (nextProp) { ensureListeningTo(rootContainerElement, propKey); } + } else if (__DEV__) { + // Validate that the properties correspond to their expected values. + var serverValue; + var propertyInfo; + if ( + propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || + // Controlled attributes are not validated + // TODO: Only ignore them on controlled tags. + propKey === 'value' || + propKey === 'checked' || + propKey === 'selected' + ) { + // Noop + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + const rawHtml = nextProp ? nextProp[HTML] || '' : ''; + const serverHTML = domElement.innerHTML; + const expectedHTML = normalizeHTML(domElement, rawHtml); + if (expectedHTML !== serverHTML) { + warnForPropDifference(propKey, serverHTML, expectedHTML); + } + } else if (propKey === STYLE) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames.delete(propKey); + // TOOD: Validate style sheets. + } else if ( + isCustomComponentTag || + DOMProperty.isCustomAttribute(propKey) + ) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames.delete(propKey); + serverValue = DOMPropertyOperations.getValueForAttribute( + domElement, + propKey, + nextProp, + ); + if (nextProp !== serverValue) { + warnForPropDifference(propKey, serverValue, nextProp); + } + } else if ((propertyInfo = DOMProperty.properties[propKey])) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames.delete(propertyInfo.attributeName); + serverValue = DOMPropertyOperations.getValueForProperty( + domElement, + propKey, + nextProp, + ); + if (nextProp !== serverValue) { + warnForPropDifference(propKey, serverValue, nextProp); + } + } + } + } + + if (__DEV__) { + // $FlowFixMe - Should be inferred as not undefined. + if (extraAttributeNames.size > 0) { + // $FlowFixMe - Should be inferred as not undefined. + warnForExtraAttributes(extraAttributeNames); } } @@ -830,6 +985,90 @@ var ReactDOMFiberComponent = { return updatePayload; }, + diffHydratedText(textNode: Text, text: string): boolean { + const isDifferent = textNode.nodeValue !== text; + if (__DEV__) { + if (isDifferent) { + warnForTextDifference(textNode.nodeValue, text); + } + } + return isDifferent; + }, + + warnForDeletedHydratableElement( + parentNode: Element | Document, + child: Element, + ) { + if (__DEV__) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Did not expect server HTML to contain a <%s> in <%s>.', + child.nodeName.toLowerCase(), + parentNode.nodeName.toLowerCase(), + ); + } + }, + + warnForDeletedHydratableText(parentNode: Element | Document, child: Text) { + if (__DEV__) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Did not expect server HTML to contain the text node "%s" in <%s>.', + child.nodeValue, + parentNode.nodeName.toLowerCase(), + ); + } + }, + + warnForInsertedHydratedElement( + parentNode: Element | Document, + tag: string, + props: Object, + ) { + if (__DEV__) { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Did not find a matching <%s> in <%s>.', + tag, + parentNode.nodeName.toLowerCase(), + ); + } + }, + + warnForInsertedHydratedText(parentNode: Element | Document, text: string) { + if (__DEV__) { + if (text === '') { + // We expect to insert empty text nodes since they're not represented in + // the HTML. + // TODO: Remove this special case if we can just avoid inserting empty + // text nodes. + return; + } + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning( + false, + 'Did not find a matching text node for "%s" in <%s>.', + text, + parentNode.nodeName.toLowerCase(), + ); + } + }, + restoreControlledState( domElement: Element, tag: string, diff --git a/src/renderers/dom/fiber/ReactDOMFiberEntry.js b/src/renderers/dom/fiber/ReactDOMFiberEntry.js index 3a5196803bb..12ab9ef8d08 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberEntry.js +++ b/src/renderers/dom/fiber/ReactDOMFiberEntry.js @@ -51,6 +51,11 @@ var { diffProperties, updateProperties, diffHydratedProperties, + diffHydratedText, + warnForDeletedHydratableElement, + warnForDeletedHydratableText, + warnForInsertedHydratedElement, + warnForInsertedHydratedText, } = ReactDOMFiberComponent; var {precacheFiberNode, updateFiberProps} = ReactDOMComponentTree; @@ -314,6 +319,7 @@ var DOMRenderer = ReactFiberReconciler({ shouldSetTextContent(type: string, props: Props): boolean { return ( + type === 'textarea' || typeof props.children === 'string' || typeof props.children === 'number' || (typeof props.dangerouslySetInnerHTML === 'object' && @@ -475,7 +481,33 @@ var DOMRenderer = ReactFiberReconciler({ internalInstanceHandle: Object, ): boolean { precacheFiberNode(internalInstanceHandle, textInstance); - return textInstance.nodeValue !== text; + return diffHydratedText(textInstance, text); + }, + + didNotHydrateInstance( + parentInstance: Instance | Container, + instance: Instance | TextInstance, + ) { + if (instance.nodeType === 1) { + warnForDeletedHydratableElement(parentInstance, (instance: any)); + } else { + warnForDeletedHydratableText(parentInstance, (instance: any)); + } + }, + + didNotFindHydratableInstance( + parentInstance: Instance | Container, + type: string, + props: Props, + ) { + warnForInsertedHydratedElement(parentInstance, type, props); + }, + + didNotFindHydratableTextInstance( + parentInstance: Instance | Container, + text: string, + ) { + warnForInsertedHydratedText(parentInstance, text); }, scheduleDeferredCallback: ReactDOMFrameScheduling.rIC, diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js index 26e9e6c5931..94b751e67dd 100644 --- a/src/renderers/dom/shared/DOMPropertyOperations.js +++ b/src/renderers/dom/shared/DOMPropertyOperations.js @@ -128,6 +128,90 @@ var DOMPropertyOperations = { return name + '=' + quoteAttributeValueForBrowser(value); }, + /** + * Get the value for a property on a node. Only used in DEV for SSR validation. + * The "expected" argument is used as a hint of what the expected value is. + * Some properties have multiple equivalent values. + */ + getValueForProperty: function(node, name, expected) { + if (__DEV__) { + var propertyInfo = DOMProperty.properties.hasOwnProperty(name) + ? DOMProperty.properties[name] + : null; + if (propertyInfo) { + var mutationMethod = propertyInfo.mutationMethod; + if (mutationMethod || propertyInfo.mustUseProperty) { + return node[propertyInfo.propertyName]; + } else { + var attributeName = propertyInfo.attributeName; + + var stringValue = null; + + if (propertyInfo.hasOverloadedBooleanValue) { + if (node.hasAttribute(attributeName)) { + var value = node.getAttribute(attributeName); + if (value === '') { + return true; + } + return value; + } + } else if (node.hasAttribute(attributeName)) { + if (shouldIgnoreValue(propertyInfo, expected)) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return node.getAttribute(attributeName); + } + if (propertyInfo.hasBooleanValue) { + // If this was a boolean, it doesn't matter what the value is + // the fact that we have it is the same as the expected. + return expected; + } + // Even if this property uses a namespace we use getAttribute + // because we assume its namespaced name is the same as our config. + // To use getAttributeNS we need the local name which we don't have + // in our config atm. + stringValue = node.getAttribute(attributeName); + } + + if (shouldIgnoreValue(propertyInfo, expected)) { + return stringValue === null ? expected : stringValue; + } else if (stringValue === '' + expected) { + return expected; + } else { + return stringValue; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + return DOMPropertyOperations.diffValueForAttribute( + node, + name, + expected, + ); + } + } + }, + + /** + * Get the value for a attribute on a node. Only used in DEV for SSR validation. + * The third argument is used as a hint of what the expected value is. Some + * attributes have multiple equivalent values. + */ + getValueForAttribute: function(node, name, expected) { + if (__DEV__) { + if (!isAttributeNameSafe(name)) { + return; + } + if (!node.hasAttribute(name)) { + return expected === undefined ? undefined : null; + } + var value = node.getAttribute(name); + if (value === '' + expected) { + return expected; + } + return value; + } + }, + /** * Sets the value for a property on a node. * diff --git a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js index 849f8ec6e53..2fd7ae39806 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js @@ -2142,7 +2142,12 @@ describe('ReactDOMServerIntegration', () => { )); it('can distinguish an empty component from an empty text component', () => - expectMarkupMismatch(
,
{''}
)); + (ReactDOMFeatureFlags.useFiber + ? expectMarkupMatch + : expectMarkupMismatch)( +
, +
{''}
, + )); }); // Markup Mismatches: misc diff --git a/src/renderers/dom/shared/__tests__/ReactMount-test.js b/src/renderers/dom/shared/__tests__/ReactMount-test.js index 077070008ae..05c798d6bdf 100644 --- a/src/renderers/dom/shared/__tests__/ReactMount-test.js +++ b/src/renderers/dom/shared/__tests__/ReactMount-test.js @@ -153,6 +153,8 @@ describe('ReactMount', () => { ReactDOM.render(
, container); expectDev(console.error.calls.count()).toBe(1); + ReactDOM.unmountComponentAtNode(container); + container.innerHTML = ' ' + ReactDOMServer.renderToString(
); ReactDOM.render(
, container); @@ -194,10 +196,17 @@ describe('ReactMount', () => { div, ); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - ' (client) nbsp entity:   client text
\n' + - ' (server) nbsp entity:   server text
', - ); + if (ReactDOMFeatureFlags.useFiber) { + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'Server: "This markup contains an nbsp entity:   server text" ' + + 'Client: "This markup contains an nbsp entity:   client text"', + ); + } else { + expectDev(console.error.calls.argsFor(0)[0]).toContain( + ' (client) nbsp entity:   client text
\n' + + ' (server) nbsp entity:   server text', + ); + } }); if (WebComponents !== undefined) { diff --git a/src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js b/src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js index 11c9dc6a45e..21089d76382 100644 --- a/src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js +++ b/src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js @@ -207,8 +207,13 @@ describe('rendering React components at document', () => { var testDocument = getTestDocument(markup); if (ReactDOMFeatureFlags.useFiber) { + spyOn(console, 'error'); ReactDOM.render(, testDocument); expect(testDocument.body.innerHTML).toBe('Hello world'); + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'Warning: Text content did not match.', + ); } else { expect(function() { // Notice the text is different! diff --git a/src/renderers/shared/fiber/ReactFiberHydrationContext.js b/src/renderers/shared/fiber/ReactFiberHydrationContext.js index ab0b98fcb25..e18160a50df 100644 --- a/src/renderers/shared/fiber/ReactFiberHydrationContext.js +++ b/src/renderers/shared/fiber/ReactFiberHydrationContext.js @@ -42,6 +42,9 @@ module.exports = function( getFirstHydratableChild, hydrateInstance, hydrateTextInstance, + didNotHydrateInstance, + didNotFindHydratableInstance, + didNotFindHydratableTextInstance, } = config; // If this doesn't have hydration mode. @@ -51,7 +54,10 @@ module.exports = function( getNextHydratableSibling && getFirstHydratableChild && hydrateInstance && - hydrateTextInstance) + hydrateTextInstance && + didNotHydrateInstance && + didNotFindHydratableInstance && + didNotFindHydratableTextInstance) ) { return { enterHydrationState() { @@ -86,6 +92,17 @@ module.exports = function( } function deleteHydratableInstance(returnFiber: Fiber, instance: I | TI) { + if (__DEV__) { + switch (returnFiber.tag) { + case HostRoot: + didNotHydrateInstance(returnFiber.stateNode.containerInfo, instance); + break; + case HostComponent: + didNotHydrateInstance(returnFiber.stateNode, instance); + break; + } + } + const childToDelete = createFiberFromHostInstanceForDeletion(); childToDelete.stateNode = instance; childToDelete.return = returnFiber; @@ -104,6 +121,38 @@ module.exports = function( } } + function insertNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) { + fiber.effectTag |= Placement; + if (__DEV__) { + var parentInstance; + switch (returnFiber.tag) { + // TODO: Currently we don't warn for insertions into the root because + // we always insert into the root in the non-hydrating case. We just + // delete the existing content. Reenable this once we have a better + // strategy for determining if we're hydrating or not. + // case HostRoot: + // parentInstance = returnFiber.stateNode.containerInfo; + // break; + case HostComponent: + parentInstance = returnFiber.stateNode; + break; + default: + return; + } + switch (fiber.tag) { + case HostComponent: + const type = fiber.type; + const props = fiber.pendingProps; + didNotFindHydratableInstance(parentInstance, type, props); + break; + case HostText: + const text = fiber.pendingProps; + didNotFindHydratableTextInstance(parentInstance, text); + break; + } + } + } + function canHydrate(fiber, nextInstance) { switch (fiber.tag) { case HostComponent: { @@ -127,7 +176,7 @@ module.exports = function( let nextInstance = nextHydratableInstance; if (!nextInstance) { // Nothing to hydrate. Make it an insertion. - fiber.effectTag |= Placement; + insertNonHydratedInstance((hydrationParentFiber: any), fiber); isHydrating = false; hydrationParentFiber = fiber; return; @@ -139,7 +188,7 @@ module.exports = function( nextInstance = getNextHydratableSibling(nextInstance); if (!nextInstance || !canHydrate(fiber, nextInstance)) { // Nothing to hydrate. Make it an insertion. - fiber.effectTag |= Placement; + insertNonHydratedInstance((hydrationParentFiber: any), fiber); isHydrating = false; hydrationParentFiber = fiber; return; diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js index 71b5ff2fbbc..d2f38655226 100644 --- a/src/renderers/shared/fiber/ReactFiberReconciler.js +++ b/src/renderers/shared/fiber/ReactFiberReconciler.js @@ -138,6 +138,16 @@ export type HostConfig = { text: string, internalInstanceHandle: OpaqueHandle, ) => boolean, + didNotHydrateInstance?: (parentInstance: I | C, instance: I | TI) => void, + didNotFindHydratableInstance?: ( + parentInstance: I | C, + type: T, + props: P, + ) => void, + didNotFindHydratableTextInstance?: ( + parentInstance: I | C, + text: string, + ) => void, useSyncScheduling?: boolean, };