@samitouri / QOS-React / commits / 8d61138186

Warn When The HTML Mismatches in DEV (#10026)

* Warn for text content * Warn for different attributes/properties values Warns if there are unknown extra attributes in the hydrated node. It also tries to compare the existing property or attribute against the expected value. It does this by reading the property and comparing it to the prop. Except it's not that simple because multiple prop values can yield the same output. For this we pass an extra expected value that is a hint as to which one was used. This is a bit weird but I'm not sure the alternatives were much better. * Warn when there is an insertion or deletion during hydration This warns if there is ever an insertion or deletion due to hydration failing to find a match. Currently we can't warn for insertions required into the root because that's how we do all non-hydrating renders atm. Left a todo. This strategy is a bit unfortunate that it leads to so much plumbing code. And we have to add three extra methods to the HostConfig that are only used in DEV and not for anything else. I don't really have a better idea. * Don't try to delete children of a textarea Textareas are special cases. The initial mount inserts children as the default value, but we should leave that untouched. This is the same as the special case where we set text content of children so I'll use that mechanism. * Change expected format for text differences In Stack this is presented as HTML which needs to have normalized escaping rules. In Fiber it is currently not presented as HTML but a raw string so we don't escape it. * Unmount component in between tests In Fiber, the second warning isn't issued because it's considered an update not a new initial render and we don't fire the warning for those. * Change expectation of white space text behavior in Fiber In Fiber we don't expect empty strings to be different from rendering null. In fact, in a follow up I plan on formalizing this by never creating text Fibers for empty strings. * Warn for different dangerouslySetInnerHTML We can't just compare the raw innerHTML value because it will have been normalized. Instead, we'll create another element, set its innerHTML and read it back. Since there can be custom elements registered with this document, we want to avoid any side-effects they might cause. So I do this in a fresh new document. I'm not sure how this would affect controlled components and other stuff that could have changed after runtime. I think for those cases maybe we just need a general way of opting out of the diff.

Sebastian Markbåge committed Jun 29, 2017 at 19:47 UTC 8d61138186e79e1e719786c8c76186e64b603bd5
10 files changed +585 -158
scripts/fiber/tests-passing-except-dev.txt
-149
@@ -3,152 +3,3 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
3 * gives source code refs for unknown prop warning for exact elements (ssr)
4 * gives source code refs for unknown prop warning for exact elements in composition (ssr)
5 * should suggest property name if available (ssr)
6 -
7 -src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
8 -* renders a blank div with client render on top of bad server markup
9 -* renders a div with inline styles with client render on top of bad server markup
10 -* renders a self-closing tag with client render on top of bad server markup
11 -* renders a self-closing tag as a child with client render on top of bad server markup
12 -* renders simple numbers with client render on top of bad server markup
13 -* renders simple strings with client render on top of bad server markup
14 -* renders string prop with true value with client render on top of bad server markup
15 -* renders string prop with false value with client render on top of bad server markup
16 -* renders boolean prop with true value with client render on top of bad server markup
17 -* renders boolean prop with false value with client render on top of bad server markup
18 -* renders boolean prop with self value with client render on top of bad server markup
19 -* renders boolean prop with "" value with client render on top of bad server markup
20 -* renders boolean prop with string value with client render on top of bad server markup
21 -* renders boolean prop with array value with client render on top of bad server markup
22 -* renders boolean prop with object value with client render on top of bad server markup
23 -* renders boolean prop with non-zero number value with client render on top of bad server markup
24 -* renders boolean prop with zero value with client render on top of bad server markup
25 -* renders download prop with true value with client render on top of bad server markup
26 -* renders download prop with false value with client render on top of bad server markup
27 -* renders download prop with string value with client render on top of bad server markup
28 -* renders download prop with string "true" value with client render on top of bad server markup
29 -* renders className prop with string value with client render on top of bad server markup
30 -* renders className prop with empty string value with client render on top of bad server markup
31 -* renders className prop with true value with client render on top of bad server markup
32 -* renders className prop with false value with client render on top of bad server markup
33 -* renders htmlFor with string value with client render on top of bad server markup
34 -* renders htmlFor with an empty string with client render on top of bad server markup
35 -* renders className prop with true value with client render on top of bad server markup
36 -* renders className prop with false value with client render on top of bad server markup
37 -* renders no ref attribute with client render on top of bad server markup
38 -* renders no children attribute with client render on top of bad server markup
39 -* renders no key attribute with client render on top of bad server markup
40 -* renders no dangerouslySetInnerHTML attribute with client render on top of bad server markup
41 -* renders no unknown attributes with client render on top of bad server markup
42 -* renders unknown data- attributes with client render on top of bad server markup
43 -* renders no unknown attributes for non-standard elements with client render on top of bad server markup
44 -* renders unknown attributes for custom elements with client render on top of bad server markup
45 -* renders unknown attributes for custom elements using is with client render on top of bad server markup
46 -* renders no HTML events with client render on top of bad server markup
47 -* renders a div with text with client render on top of bad server markup
48 -* renders a div with text with flanking whitespace with client render on top of bad server markup
49 -* renders a div with an empty text child with client render on top of bad server markup
50 -* renders a div with multiple empty text children with client render on top of bad server markup
51 -* renders a div with multiple whitespace children with client render on top of bad server markup
52 -* renders a div with text sibling to a node with client render on top of bad server markup
53 -* renders a non-standard element with text with client render on top of bad server markup
54 -* renders a custom element with text with client render on top of bad server markup
55 -* renders a leading blank child with a text sibling with client render on top of bad server markup
56 -* renders a trailing blank child with a text sibling with client render on top of bad server markup
57 -* renders an element with two text children with client render on top of bad server markup
58 -* renders a number as single child with client render on top of bad server markup
59 -* renders zero as single child with client render on top of bad server markup
60 -* renders an element with number and text children with client render on top of bad server markup
61 -* renders null single child as blank with client render on top of bad server markup
62 -* renders false single child as blank with client render on top of bad server markup
63 -* renders undefined single child as blank with client render on top of bad server markup
64 -* renders a null component children as empty with client render on top of bad server markup
65 -* renders null children as blank with client render on top of bad server markup
66 -* renders false children as blank with client render on top of bad server markup
67 -* renders null and false children together as blank with client render on top of bad server markup
68 -* renders only null and false children as blank with client render on top of bad server markup
69 -* renders an svg element with client render on top of bad server markup
70 -* renders svg element with an xlink with client render on top of bad server markup
71 -* renders a math element with client render on top of bad server markup
72 -* renders an img with client render on top of bad server markup
73 -* renders a button with client render on top of bad server markup
74 -* renders a div with dangerouslySetInnerHTML with client render on top of bad server markup
75 -* renders a newline-eating tag with content not starting with \n with client render on top of bad server markup
76 -* renders a newline-eating tag with content starting with \n with client render on top of bad server markup
77 -* renders a normal tag with content starting with \n with client render on top of bad server markup
78 -* renders stateless components with client render on top of bad server markup
79 -* renders ES6 class components with client render on top of bad server markup
80 -* renders factory components with client render on top of bad server markup
81 -* renders single child hierarchies of components with client render on top of bad server markup
82 -* renders multi-child hierarchies of components with client render on top of bad server markup
83 -* renders a div with a child with client render on top of bad server markup
84 -* renders a div with multiple children with client render on top of bad server markup
85 -* renders a div with multiple children separated by whitespace with client render on top of bad server markup
86 -* renders a div with a single child surrounded by whitespace with client render on top of bad server markup
87 -* renders >,<, and & as single child with client render on top of bad server markup
88 -* renders >,<, and & as multiple children with client render on top of bad server markup
89 -* renders an input with a value and an onChange with client render on top of bad server markup
90 -* renders an input with a value and readOnly with client render on top of bad server markup
91 -* renders an input with a value and no onChange/readOnly with client render on top of bad server markup
92 -* renders an input with a defaultValue with client render on top of bad server markup
93 -* renders an input value overriding defaultValue with client render on top of bad server markup
94 -* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup
95 -* renders a checkbox that is checked with an onChange with client render on top of bad server markup
96 -* renders a checkbox that is checked with readOnly with client render on top of bad server markup
97 -* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup
98 -* renders a checkbox with defaultChecked with client render on top of bad server markup
99 -* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup
100 -* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup
101 -* renders a textarea with a value and an onChange with client render on top of bad server markup
102 -* renders a textarea with a value and readOnly with client render on top of bad server markup
103 -* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup
104 -* renders a textarea with a defaultValue with client render on top of bad server markup
105 -* renders a textarea value overriding defaultValue with client render on top of bad server markup
106 -* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup
107 -* renders a select with a value and an onChange with client render on top of bad server markup
108 -* renders a select with a value and readOnly with client render on top of bad server markup
109 -* renders a select with a multiple values and an onChange with client render on top of bad server markup
110 -* renders a select with a multiple values and readOnly with client render on top of bad server markup
111 -* renders a select with a value and no onChange/readOnly with client render on top of bad server markup
112 -* renders a select with a defaultValue with client render on top of bad server markup
113 -* renders a select value overriding defaultValue with client render on top of bad server markup
114 -* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup
115 -* renders a controlled text input with client render on top of bad server markup
116 -* renders a controlled textarea with client render on top of bad server markup
117 -* renders a controlled checkbox with client render on top of bad server markup
118 -* renders a controlled select with client render on top of bad server markup
119 -* renders class child with context with client render on top of bad server markup
120 -* renders stateless child with context with client render on top of bad server markup
121 -* renders class child without context with client render on top of bad server markup
122 -* renders stateless child without context with client render on top of bad server markup
123 -* renders class child with wrong context with client render on top of bad server markup
124 -* renders stateless child with wrong context with client render on top of bad server markup
125 -* renders with context passed through to a grandchild with client render on top of bad server markup
126 -* renders a child context overriding a parent context with client render on top of bad server markup
127 -* renders a child context merged with a parent context with client render on top of bad server markup
128 -* renders with a call to componentWillMount before getChildContext with client render on top of bad server markup
129 -* should error reconnecting different element types
130 -* should error reconnecting missing attributes
131 -* should error reconnecting added attributes
132 -* should error reconnecting different attribute values
133 -* should error reconnecting different text
134 -* should error reconnecting different numbers
135 -* should error reconnecting different number from text
136 -* should error reconnecting different text in two code blocks
137 -* should error reconnecting missing children
138 -* should error reconnecting added children
139 -* should error reconnecting more children
140 -* should error reconnecting fewer children
141 -* should error reconnecting reordered children
142 -* should error reconnecting a div with children separated by whitespace on the client
143 -* should error reconnecting a div with children separated by different whitespace on the server
144 -* should error reconnecting a div with children separated by different whitespace
145 -* can distinguish an empty component from a dom node
146 -* can distinguish an empty component from an empty text component
147 -* should error reconnecting a div with different dangerouslySetInnerHTML
148 -
149 -src/renderers/dom/shared/__tests__/ReactMount-test.js
150 -* should warn if mounting into dirty rendered markup
151 -* should account for escaping on a checksum mismatch
152 -
153 -src/renderers/dom/shared/__tests__/ReactServerRendering-test.js
154 -* should have the correct mounting behavior
scripts/fiber/tests-passing.txt
+143
@@ -885,326 +885,407 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
885 * renders a blank div with server stream render
886 * renders a blank div with clean client render
887 * renders a blank div with client render on top of good server markup
888 +* renders a blank div with client render on top of bad server markup
889 * renders a div with inline styles with server string render
890 * renders a div with inline styles with server stream render
891 * renders a div with inline styles with clean client render
892 * renders a div with inline styles with client render on top of good server markup
893 +* renders a div with inline styles with client render on top of bad server markup
894 * renders a self-closing tag with server string render
895 * renders a self-closing tag with server stream render
896 * renders a self-closing tag with clean client render
897 * renders a self-closing tag with client render on top of good server markup
898 +* renders a self-closing tag with client render on top of bad server markup
899 * renders a self-closing tag as a child with server string render
900 * renders a self-closing tag as a child with server stream render
901 * renders a self-closing tag as a child with clean client render
902 * renders a self-closing tag as a child with client render on top of good server markup
903 +* renders a self-closing tag as a child with client render on top of bad server markup
904 * renders simple numbers with server string render
905 * renders simple numbers with server stream render
906 * renders simple numbers with clean client render
907 * renders simple numbers with client render on top of good server markup
908 +* renders simple numbers with client render on top of bad server markup
909 * renders simple strings with server string render
910 * renders simple strings with server stream render
911 * renders simple strings with clean client render
912 * renders simple strings with client render on top of good server markup
913 +* renders simple strings with client render on top of bad server markup
914 * renders string prop with true value with server string render
915 * renders string prop with true value with server stream render
916 * renders string prop with true value with clean client render
917 * renders string prop with true value with client render on top of good server markup
918 +* renders string prop with true value with client render on top of bad server markup
919 * renders string prop with false value with server string render
920 * renders string prop with false value with server stream render
921 * renders string prop with false value with clean client render
922 * renders string prop with false value with client render on top of good server markup
923 +* renders string prop with false value with client render on top of bad server markup
924 * renders boolean prop with true value with server string render
925 * renders boolean prop with true value with server stream render
926 * renders boolean prop with true value with clean client render
927 * renders boolean prop with true value with client render on top of good server markup
928 +* renders boolean prop with true value with client render on top of bad server markup
929 * renders boolean prop with false value with server string render
930 * renders boolean prop with false value with server stream render
931 * renders boolean prop with false value with clean client render
932 * renders boolean prop with false value with client render on top of good server markup
933 +* renders boolean prop with false value with client render on top of bad server markup
934 * renders boolean prop with self value with server string render
935 * renders boolean prop with self value with server stream render
936 * renders boolean prop with self value with clean client render
937 * renders boolean prop with self value with client render on top of good server markup
938 +* renders boolean prop with self value with client render on top of bad server markup
939 * renders boolean prop with "" value with server string render
940 * renders boolean prop with "" value with server stream render
941 * renders boolean prop with "" value with clean client render
942 * renders boolean prop with "" value with client render on top of good server markup
943 +* renders boolean prop with "" value with client render on top of bad server markup
944 * renders boolean prop with string value with server string render
945 * renders boolean prop with string value with server stream render
946 * renders boolean prop with string value with clean client render
947 * renders boolean prop with string value with client render on top of good server markup
948 +* renders boolean prop with string value with client render on top of bad server markup
949 * renders boolean prop with array value with server string render
950 * renders boolean prop with array value with server stream render
951 * renders boolean prop with array value with clean client render
952 * renders boolean prop with array value with client render on top of good server markup
953 +* renders boolean prop with array value with client render on top of bad server markup
954 * renders boolean prop with object value with server string render
955 * renders boolean prop with object value with server stream render
956 * renders boolean prop with object value with clean client render
957 * renders boolean prop with object value with client render on top of good server markup
958 +* renders boolean prop with object value with client render on top of bad server markup
959 * renders boolean prop with non-zero number value with server string render
960 * renders boolean prop with non-zero number value with server stream render
961 * renders boolean prop with non-zero number value with clean client render
962 * renders boolean prop with non-zero number value with client render on top of good server markup
963 +* renders boolean prop with non-zero number value with client render on top of bad server markup
964 * renders boolean prop with zero value with server string render
965 * renders boolean prop with zero value with server stream render
966 * renders boolean prop with zero value with clean client render
967 * renders boolean prop with zero value with client render on top of good server markup
968 +* renders boolean prop with zero value with client render on top of bad server markup
969 * renders download prop with true value with server string render
970 * renders download prop with true value with server stream render
971 * renders download prop with true value with clean client render
972 * renders download prop with true value with client render on top of good server markup
973 +* renders download prop with true value with client render on top of bad server markup
974 * renders download prop with false value with server string render
975 * renders download prop with false value with server stream render
976 * renders download prop with false value with clean client render
977 * renders download prop with false value with client render on top of good server markup
978 +* renders download prop with false value with client render on top of bad server markup
979 * renders download prop with string value with server string render
980 * renders download prop with string value with server stream render
981 * renders download prop with string value with clean client render
982 * renders download prop with string value with client render on top of good server markup
983 +* renders download prop with string value with client render on top of bad server markup
984 * renders download prop with string "true" value with server string render
985 * renders download prop with string "true" value with server stream render
986 * renders download prop with string "true" value with clean client render
987 * renders download prop with string "true" value with client render on top of good server markup
988 +* renders download prop with string "true" value with client render on top of bad server markup
989 * renders className prop with string value with server string render
990 * renders className prop with string value with server stream render
991 * renders className prop with string value with clean client render
992 * renders className prop with string value with client render on top of good server markup
993 +* renders className prop with string value with client render on top of bad server markup
994 * renders className prop with empty string value with server string render
995 * renders className prop with empty string value with server stream render
996 * renders className prop with empty string value with clean client render
997 * renders className prop with empty string value with client render on top of good server markup
998 +* renders className prop with empty string value with client render on top of bad server markup
999 * renders className prop with true value with server string render
1000 * renders className prop with true value with server stream render
1001 * renders className prop with true value with clean client render
1002 * renders className prop with true value with client render on top of good server markup
1003 +* renders className prop with true value with client render on top of bad server markup
1004 * renders className prop with false value with server string render
1005 * renders className prop with false value with server stream render
1006 * renders className prop with false value with clean client render
1007 * renders className prop with false value with client render on top of good server markup
1008 +* renders className prop with false value with client render on top of bad server markup
1009 * renders htmlFor with string value with server string render
1010 * renders htmlFor with string value with server stream render
1011 * renders htmlFor with string value with clean client render
1012 * renders htmlFor with string value with client render on top of good server markup
1013 +* renders htmlFor with string value with client render on top of bad server markup
1014 * renders htmlFor with an empty string with server string render
1015 * renders htmlFor with an empty string with server stream render
1016 * renders htmlFor with an empty string with clean client render
1017 * renders htmlFor with an empty string with client render on top of good server markup
1018 +* renders htmlFor with an empty string with client render on top of bad server markup
1019 * renders className prop with true value with server string render
1020 * renders className prop with true value with server stream render
1021 * renders className prop with true value with clean client render
1022 * renders className prop with true value with client render on top of good server markup
1023 +* renders className prop with true value with client render on top of bad server markup
1024 * renders className prop with false value with server string render
1025 * renders className prop with false value with server stream render
1026 * renders className prop with false value with clean client render
1027 * renders className prop with false value with client render on top of good server markup
1028 +* renders className prop with false value with client render on top of bad server markup
1029 * renders no ref attribute with server string render
1030 * renders no ref attribute with server stream render
1031 * renders no ref attribute with clean client render
1032 * renders no ref attribute with client render on top of good server markup
1033 +* renders no ref attribute with client render on top of bad server markup
1034 * renders no children attribute with server string render
1035 * renders no children attribute with server stream render
1036 * renders no children attribute with clean client render
1037 * renders no children attribute with client render on top of good server markup
1038 +* renders no children attribute with client render on top of bad server markup
1039 * renders no key attribute with server string render
1040 * renders no key attribute with server stream render
1041 * renders no key attribute with clean client render
1042 * renders no key attribute with client render on top of good server markup
1043 +* renders no key attribute with client render on top of bad server markup
1044 * renders no dangerouslySetInnerHTML attribute with server string render
1045 * renders no dangerouslySetInnerHTML attribute with server stream render
1046 * renders no dangerouslySetInnerHTML attribute with clean client render
1047 * renders no dangerouslySetInnerHTML attribute with client render on top of good server markup
1048 +* renders no dangerouslySetInnerHTML attribute with client render on top of bad server markup
1049 * renders no unknown attributes with server string render
1050 * renders no unknown attributes with server stream render
1051 * renders no unknown attributes with clean client render
1052 * renders no unknown attributes with client render on top of good server markup
1053 +* renders no unknown attributes with client render on top of bad server markup
1054 * renders unknown data- attributes with server string render
1055 * renders unknown data- attributes with server stream render
1056 * renders unknown data- attributes with clean client render
1057 * renders unknown data- attributes with client render on top of good server markup
1058 +* renders unknown data- attributes with client render on top of bad server markup
1059 * renders no unknown attributes for non-standard elements with server string render
1060 * renders no unknown attributes for non-standard elements with server stream render
1061 * renders no unknown attributes for non-standard elements with clean client render
1062 * renders no unknown attributes for non-standard elements with client render on top of good server markup
1063 +* renders no unknown attributes for non-standard elements with client render on top of bad server markup
1064 * renders unknown attributes for custom elements with server string render
1065 * renders unknown attributes for custom elements with server stream render
1066 * renders unknown attributes for custom elements with clean client render
1067 * renders unknown attributes for custom elements with client render on top of good server markup
1068 +* renders unknown attributes for custom elements with client render on top of bad server markup
1069 * renders unknown attributes for custom elements using is with server string render
1070 * renders unknown attributes for custom elements using is with server stream render
1071 * renders unknown attributes for custom elements using is with clean client render
1072 * renders unknown attributes for custom elements using is with client render on top of good server markup
1073 +* renders unknown attributes for custom elements using is with client render on top of bad server markup
1074 * renders no HTML events with server string render
1075 * renders no HTML events with server stream render
1076 * renders no HTML events with clean client render
1077 * renders no HTML events with client render on top of good server markup
1078 +* renders no HTML events with client render on top of bad server markup
1079 * renders a div with text with server string render
1080 * renders a div with text with server stream render
1081 * renders a div with text with clean client render
1082 * renders a div with text with client render on top of good server markup
1083 +* renders a div with text with client render on top of bad server markup
1084 * renders a div with text with flanking whitespace with server string render
1085 * renders a div with text with flanking whitespace with server stream render
1086 * renders a div with text with flanking whitespace with clean client render
1087 * renders a div with text with flanking whitespace with client render on top of good server markup
1088 +* renders a div with text with flanking whitespace with client render on top of bad server markup
1089 * renders a div with an empty text child with server string render
1090 * renders a div with an empty text child with server stream render
1091 * renders a div with an empty text child with clean client render
1092 * renders a div with an empty text child with client render on top of good server markup
1093 +* renders a div with an empty text child with client render on top of bad server markup
1094 * renders a div with multiple empty text children with server string render
1095 * renders a div with multiple empty text children with server stream render
1096 * renders a div with multiple empty text children with clean client render
1097 * renders a div with multiple empty text children with client render on top of good server markup
1098 +* renders a div with multiple empty text children with client render on top of bad server markup
1099 * renders a div with multiple whitespace children with server string render
1100 * renders a div with multiple whitespace children with server stream render
1101 * renders a div with multiple whitespace children with clean client render
1102 * renders a div with multiple whitespace children with client render on top of good server markup
1103 +* renders a div with multiple whitespace children with client render on top of bad server markup
1104 * renders a div with text sibling to a node with server string render
1105 * renders a div with text sibling to a node with server stream render
1106 * renders a div with text sibling to a node with clean client render
1107 * renders a div with text sibling to a node with client render on top of good server markup
1108 +* renders a div with text sibling to a node with client render on top of bad server markup
1109 * renders a non-standard element with text with server string render
1110 * renders a non-standard element with text with server stream render
1111 * renders a non-standard element with text with clean client render
1112 * renders a non-standard element with text with client render on top of good server markup
1113 +* renders a non-standard element with text with client render on top of bad server markup
1114 * renders a custom element with text with server string render
1115 * renders a custom element with text with server stream render
1116 * renders a custom element with text with clean client render
1117 * renders a custom element with text with client render on top of good server markup
1118 +* renders a custom element with text with client render on top of bad server markup
1119 * renders a leading blank child with a text sibling with server string render
1120 * renders a leading blank child with a text sibling with server stream render
1121 * renders a leading blank child with a text sibling with clean client render
1122 * renders a leading blank child with a text sibling with client render on top of good server markup
1123 +* renders a leading blank child with a text sibling with client render on top of bad server markup
1124 * renders a trailing blank child with a text sibling with server string render
1125 * renders a trailing blank child with a text sibling with server stream render
1126 * renders a trailing blank child with a text sibling with clean client render
1127 * renders a trailing blank child with a text sibling with client render on top of good server markup
1128 +* renders a trailing blank child with a text sibling with client render on top of bad server markup
1129 * renders an element with two text children with server string render
1130 * renders an element with two text children with server stream render
1131 * renders an element with two text children with clean client render
1132 * renders an element with two text children with client render on top of good server markup
1133 +* renders an element with two text children with client render on top of bad server markup
1134 * renders a number as single child with server string render
1135 * renders a number as single child with server stream render
1136 * renders a number as single child with clean client render
1137 * renders a number as single child with client render on top of good server markup
1138 +* renders a number as single child with client render on top of bad server markup
1139 * renders zero as single child with server string render
1140 * renders zero as single child with server stream render
1141 * renders zero as single child with clean client render
1142 * renders zero as single child with client render on top of good server markup
1143 +* renders zero as single child with client render on top of bad server markup
1144 * renders an element with number and text children with server string render
1145 * renders an element with number and text children with server stream render
1146 * renders an element with number and text children with clean client render
1147 * renders an element with number and text children with client render on top of good server markup
1148 +* renders an element with number and text children with client render on top of bad server markup
1149 * renders null single child as blank with server string render
1150 * renders null single child as blank with server stream render
1151 * renders null single child as blank with clean client render
1152 * renders null single child as blank with client render on top of good server markup
1153 +* renders null single child as blank with client render on top of bad server markup
1154 * renders false single child as blank with server string render
1155 * renders false single child as blank with server stream render
1156 * renders false single child as blank with clean client render
1157 * renders false single child as blank with client render on top of good server markup
1158 +* renders false single child as blank with client render on top of bad server markup
1159 * renders undefined single child as blank with server string render
1160 * renders undefined single child as blank with server stream render
1161 * renders undefined single child as blank with clean client render
1162 * renders undefined single child as blank with client render on top of good server markup
1163 +* renders undefined single child as blank with client render on top of bad server markup
1164 * renders a null component children as empty with server string render
1165 * renders a null component children as empty with server stream render
1166 * renders a null component children as empty with clean client render
1167 * renders a null component children as empty with client render on top of good server markup
1168 +* renders a null component children as empty with client render on top of bad server markup
1169 * renders null children as blank with server string render
1170 * renders null children as blank with server stream render
1171 * renders null children as blank with clean client render
1172 * renders null children as blank with client render on top of good server markup
1173 +* renders null children as blank with client render on top of bad server markup
1174 * renders false children as blank with server string render
1175 * renders false children as blank with server stream render
1176 * renders false children as blank with clean client render
1177 * renders false children as blank with client render on top of good server markup
1178 +* renders false children as blank with client render on top of bad server markup
1179 * renders null and false children together as blank with server string render
1180 * renders null and false children together as blank with server stream render
1181 * renders null and false children together as blank with clean client render
1182 * renders null and false children together as blank with client render on top of good server markup
1183 +* renders null and false children together as blank with client render on top of bad server markup
1184 * renders only null and false children as blank with server string render
1185 * renders only null and false children as blank with server stream render
1186 * renders only null and false children as blank with clean client render
1187 * renders only null and false children as blank with client render on top of good server markup
1188 +* renders only null and false children as blank with client render on top of bad server markup
1189 * renders an svg element with server string render
1190 * renders an svg element with server stream render
1191 * renders an svg element with clean client render
1192 * renders an svg element with client render on top of good server markup
1193 +* renders an svg element with client render on top of bad server markup
1194 * renders svg element with an xlink with server string render
1195 * renders svg element with an xlink with server stream render
1196 * renders svg element with an xlink with clean client render
1197 * renders svg element with an xlink with client render on top of good server markup
1198 +* renders svg element with an xlink with client render on top of bad server markup
1199 * renders a math element with server string render
1200 * renders a math element with server stream render
1201 * renders a math element with clean client render
1202 * renders a math element with client render on top of good server markup
1203 +* renders a math element with client render on top of bad server markup
1204 * renders an img with server string render
1205 * renders an img with server stream render
1206 * renders an img with clean client render
1207 * renders an img with client render on top of good server markup
1208 +* renders an img with client render on top of bad server markup
1209 * renders a button with server string render
1210 * renders a button with server stream render
1211 * renders a button with clean client render
1212 * renders a button with client render on top of good server markup
1213 +* renders a button with client render on top of bad server markup
1214 * renders a div with dangerouslySetInnerHTML with server string render
1215 * renders a div with dangerouslySetInnerHTML with server stream render
1216 * renders a div with dangerouslySetInnerHTML with clean client render
1217 * renders a div with dangerouslySetInnerHTML with client render on top of good server markup
1218 +* renders a div with dangerouslySetInnerHTML with client render on top of bad server markup
1219 * renders a newline-eating tag with content not starting with \n with server string render
1220 * renders a newline-eating tag with content not starting with \n with server stream render
1221 * renders a newline-eating tag with content not starting with \n with clean client render
1222 * renders a newline-eating tag with content not starting with \n with client render on top of good server markup
1223 +* renders a newline-eating tag with content not starting with \n with client render on top of bad server markup
1224 * renders a newline-eating tag with content starting with \n with server string render
1225 * renders a newline-eating tag with content starting with \n with server stream render
1226 * renders a newline-eating tag with content starting with \n with clean client render
1227 * renders a newline-eating tag with content starting with \n with client render on top of good server markup
1228 +* renders a newline-eating tag with content starting with \n with client render on top of bad server markup
1229 * renders a normal tag with content starting with \n with server string render
1230 * renders a normal tag with content starting with \n with server stream render
1231 * renders a normal tag with content starting with \n with clean client render
1232 * renders a normal tag with content starting with \n with client render on top of good server markup
1233 +* renders a normal tag with content starting with \n with client render on top of bad server markup
1234 * renders stateless components with server string render
1235 * renders stateless components with server stream render
1236 * renders stateless components with clean client render
1237 * renders stateless components with client render on top of good server markup
1238 +* renders stateless components with client render on top of bad server markup
1239 * renders ES6 class components with server string render
1240 * renders ES6 class components with server stream render
1241 * renders ES6 class components with clean client render
1242 * renders ES6 class components with client render on top of good server markup
1243 +* renders ES6 class components with client render on top of bad server markup
1244 * renders factory components with server string render
1245 * renders factory components with server stream render
1246 * renders factory components with clean client render
1247 * renders factory components with client render on top of good server markup
1248 +* renders factory components with client render on top of bad server markup
1249 * renders single child hierarchies of components with server string render
1250 * renders single child hierarchies of components with server stream render
1251 * renders single child hierarchies of components with clean client render
1252 * renders single child hierarchies of components with client render on top of good server markup
1253 +* renders single child hierarchies of components with client render on top of bad server markup
1254 * renders multi-child hierarchies of components with server string render
1255 * renders multi-child hierarchies of components with server stream render
1256 * renders multi-child hierarchies of components with clean client render
1257 * renders multi-child hierarchies of components with client render on top of good server markup
1258 +* renders multi-child hierarchies of components with client render on top of bad server markup
1259 * renders a div with a child with server string render
1260 * renders a div with a child with server stream render
1261 * renders a div with a child with clean client render
1262 * renders a div with a child with client render on top of good server markup
1263 +* renders a div with a child with client render on top of bad server markup
1264 * renders a div with multiple children with server string render
1265 * renders a div with multiple children with server stream render
1266 * renders a div with multiple children with clean client render
1267 * renders a div with multiple children with client render on top of good server markup
1268 +* renders a div with multiple children with client render on top of bad server markup
1269 * renders a div with multiple children separated by whitespace with server string render
1270 * renders a div with multiple children separated by whitespace with server stream render
1271 * renders a div with multiple children separated by whitespace with clean client render
1272 * renders a div with multiple children separated by whitespace with client render on top of good server markup
1273 +* renders a div with multiple children separated by whitespace with client render on top of bad server markup
1274 * renders a div with a single child surrounded by whitespace with server string render
1275 * renders a div with a single child surrounded by whitespace with server stream render
1276 * renders a div with a single child surrounded by whitespace with clean client render
1277 * renders a div with a single child surrounded by whitespace with client render on top of good server markup
1278 +* renders a div with a single child surrounded by whitespace with client render on top of bad server markup
1279 * renders >,<, and & as single child with server string render
1280 * renders >,<, and & as single child with server stream render
1281 * renders >,<, and & as single child with clean client render
1282 * renders >,<, and & as single child with client render on top of good server markup
1283 +* renders >,<, and & as single child with client render on top of bad server markup
1284 * renders >,<, and & as multiple children with server string render
1285 * renders >,<, and & as multiple children with server stream render
1286 * renders >,<, and & as multiple children with clean client render
1287 * renders >,<, and & as multiple children with client render on top of good server markup
1288 +* renders >,<, and & as multiple children with client render on top of bad server markup
1289 * throws when rendering a string component with server string render
1290 * throws when rendering a string component with clean client render
1291 * 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
1314 * renders an input with a value and an onChange with server stream render
1315 * renders an input with a value and an onChange with clean client render
1316 * renders an input with a value and an onChange with client render on top of good server markup
1317 +* renders an input with a value and an onChange with client render on top of bad server markup
1318 * renders an input with a value and readOnly with server string render
1319 * renders an input with a value and readOnly with server stream render
1320 * renders an input with a value and readOnly with clean client render
1321 * renders an input with a value and readOnly with client render on top of good server markup
1322 +* renders an input with a value and readOnly with client render on top of bad server markup
1323 * renders an input with a value and no onChange/readOnly with server string render
1324 * renders an input with a value and no onChange/readOnly with server stream render
1325 * renders an input with a value and no onChange/readOnly with clean client render
1326 * renders an input with a value and no onChange/readOnly with client render on top of good server markup
1327 +* renders an input with a value and no onChange/readOnly with client render on top of bad server markup
1328 * renders an input with a defaultValue with server string render
1329 * renders an input with a defaultValue with server stream render
1330 * renders an input with a defaultValue with clean client render
1331 * renders an input with a defaultValue with client render on top of good server markup
1332 +* renders an input with a defaultValue with client render on top of bad server markup
1333 * renders an input value overriding defaultValue with server string render
1334 * renders an input value overriding defaultValue with server stream render
1335 * renders an input value overriding defaultValue with clean client render
1336 * renders an input value overriding defaultValue with client render on top of good server markup
1337 +* renders an input value overriding defaultValue with client render on top of bad server markup
1338 * renders an input value overriding defaultValue no matter the prop order with server string render
1339 * renders an input value overriding defaultValue no matter the prop order with server stream render
1340 * renders an input value overriding defaultValue no matter the prop order with clean client render
1341 * renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup
1342 +* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup
1343 * renders a checkbox that is checked with an onChange with server string render
1344 * renders a checkbox that is checked with an onChange with server stream render
1345 * renders a checkbox that is checked with an onChange with clean client render
1346 * renders a checkbox that is checked with an onChange with client render on top of good server markup
1347 +* renders a checkbox that is checked with an onChange with client render on top of bad server markup
1348 * renders a checkbox that is checked with readOnly with server string render
1349 * renders a checkbox that is checked with readOnly with server stream render
1350 * renders a checkbox that is checked with readOnly with clean client render
1351 * renders a checkbox that is checked with readOnly with client render on top of good server markup
1352 +* renders a checkbox that is checked with readOnly with client render on top of bad server markup
1353 * renders a checkbox that is checked and no onChange/readOnly with server string render
1354 * renders a checkbox that is checked and no onChange/readOnly with server stream render
1355 * renders a checkbox that is checked and no onChange/readOnly with clean client render
1356 * renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup
1357 +* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup
1358 * renders a checkbox with defaultChecked with server string render
1359 * renders a checkbox with defaultChecked with server stream render
1360 * renders a checkbox with defaultChecked with clean client render
1361 * renders a checkbox with defaultChecked with client render on top of good server markup
1362 +* renders a checkbox with defaultChecked with client render on top of bad server markup
1363 * renders a checkbox checked overriding defaultChecked with server string render
1364 * renders a checkbox checked overriding defaultChecked with server stream render
1365 * renders a checkbox checked overriding defaultChecked with clean client render
1366 * renders a checkbox checked overriding defaultChecked with client render on top of good server markup
1367 +* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup
1368 * renders a checkbox checked overriding defaultChecked no matter the prop order with server string render
1369 * renders a checkbox checked overriding defaultChecked no matter the prop order with server stream render
1370 * renders a checkbox checked overriding defaultChecked no matter the prop order with clean client render
1371 * renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup
1372 +* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup
1373 * renders a textarea with a value and an onChange with server string render
1374 * renders a textarea with a value and an onChange with server stream render
1375 * renders a textarea with a value and an onChange with clean client render
1376 * renders a textarea with a value and an onChange with client render on top of good server markup
1377 +* renders a textarea with a value and an onChange with client render on top of bad server markup
1378 * renders a textarea with a value and readOnly with server string render
1379 * renders a textarea with a value and readOnly with server stream render
1380 * renders a textarea with a value and readOnly with clean client render
1381 * renders a textarea with a value and readOnly with client render on top of good server markup
1382 +* renders a textarea with a value and readOnly with client render on top of bad server markup
1383 * renders a textarea with a value and no onChange/readOnly with server string render
1384 * renders a textarea with a value and no onChange/readOnly with server stream render
1385 * renders a textarea with a value and no onChange/readOnly with clean client render
1386 * renders a textarea with a value and no onChange/readOnly with client render on top of good server markup
1387 +* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup
1388 * renders a textarea with a defaultValue with server string render
1389 * renders a textarea with a defaultValue with server stream render
1390 * renders a textarea with a defaultValue with clean client render
1391 * renders a textarea with a defaultValue with client render on top of good server markup
1392 +* renders a textarea with a defaultValue with client render on top of bad server markup
1393 * renders a textarea value overriding defaultValue with server string render
1394 * renders a textarea value overriding defaultValue with server stream render
1395 * renders a textarea value overriding defaultValue with clean client render
1396 * renders a textarea value overriding defaultValue with client render on top of good server markup
1397 +* renders a textarea value overriding defaultValue with client render on top of bad server markup
1398 * renders a textarea value overriding defaultValue no matter the prop order with server string render
1399 * renders a textarea value overriding defaultValue no matter the prop order with server stream render
1400 * renders a textarea value overriding defaultValue no matter the prop order with clean client render
1401 * renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup
1402 +* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup
1403 * renders a select with a value and an onChange with server string render
1404 * renders a select with a value and an onChange with server stream render
1405 * renders a select with a value and an onChange with clean client render
1406 * renders a select with a value and an onChange with client render on top of good server markup
1407 +* renders a select with a value and an onChange with client render on top of bad server markup
1408 * renders a select with a value and readOnly with server string render
1409 * renders a select with a value and readOnly with server stream render
1410 * renders a select with a value and readOnly with clean client render
1411 * renders a select with a value and readOnly with client render on top of good server markup
1412 +* renders a select with a value and readOnly with client render on top of bad server markup
1413 * renders a select with a multiple values and an onChange with server string render
1414 * renders a select with a multiple values and an onChange with server stream render
1415 * renders a select with a multiple values and an onChange with clean client render
1416 * renders a select with a multiple values and an onChange with client render on top of good server markup
1417 +* renders a select with a multiple values and an onChange with client render on top of bad server markup
1418 * renders a select with a multiple values and readOnly with server string render
1419 * renders a select with a multiple values and readOnly with server stream render
1420 * renders a select with a multiple values and readOnly with clean client render
1421 * renders a select with a multiple values and readOnly with client render on top of good server markup
1422 +* renders a select with a multiple values and readOnly with client render on top of bad server markup
1423 * renders a select with a value and no onChange/readOnly with server string render
1424 * renders a select with a value and no onChange/readOnly with server stream render
1425 * renders a select with a value and no onChange/readOnly with clean client render
1426 * renders a select with a value and no onChange/readOnly with client render on top of good server markup
1427 +* renders a select with a value and no onChange/readOnly with client render on top of bad server markup
1428 * renders a select with a defaultValue with server string render
1429 * renders a select with a defaultValue with server stream render
1430 * renders a select with a defaultValue with clean client render
1431 * renders a select with a defaultValue with client render on top of good server markup
1432 +* renders a select with a defaultValue with client render on top of bad server markup
1433 * renders a select value overriding defaultValue with server string render
1434 * renders a select value overriding defaultValue with server stream render
1435 * renders a select value overriding defaultValue with clean client render
1436 * renders a select value overriding defaultValue with client render on top of good server markup
1437 +* renders a select value overriding defaultValue with client render on top of bad server markup
1438 * renders a select value overriding defaultValue no matter the prop order with server string render
1439 * renders a select value overriding defaultValue no matter the prop order with server stream render
1440 * renders a select value overriding defaultValue no matter the prop order with clean client render
1441 * renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup
1442 +* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup
1443 * renders a controlled text input with clean client render
1444 * renders a controlled text input with client render on top of good server markup
1445 +* renders a controlled text input with client render on top of bad server markup
1446 * renders a controlled textarea with clean client render
1447 * renders a controlled textarea with client render on top of good server markup
1448 +* renders a controlled textarea with client render on top of bad server markup
1449 * renders a controlled checkbox with clean client render
1450 * renders a controlled checkbox with client render on top of good server markup
1451 +* renders a controlled checkbox with client render on top of bad server markup
1452 * renders a controlled select with clean client render
1453 * renders a controlled select with client render on top of good server markup
1454 +* renders a controlled select with client render on top of bad server markup
1455 * should not blow away user-entered text on successful reconnect to an uncontrolled input
1456 * should not blow away user-entered text on successful reconnect to a controlled input
1457 * 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
1462 * renders class child with context with server stream render
1463 * renders class child with context with clean client render
1464 * renders class child with context with client render on top of good server markup
1465 +* renders class child with context with client render on top of bad server markup
1466 * renders stateless child with context with server string render
1467 * renders stateless child with context with server stream render
1468 * renders stateless child with context with clean client render
1469 * renders stateless child with context with client render on top of good server markup
1470 +* renders stateless child with context with client render on top of bad server markup
1471 * renders class child without context with server string render
1472 * renders class child without context with server stream render
1473 * renders class child without context with clean client render
1474 * renders class child without context with client render on top of good server markup
1475 +* renders class child without context with client render on top of bad server markup
1476 * renders stateless child without context with server string render
1477 * renders stateless child without context with server stream render
1478 * renders stateless child without context with clean client render
1479 * renders stateless child without context with client render on top of good server markup
1480 +* renders stateless child without context with client render on top of bad server markup
1481 * renders class child with wrong context with server string render
1482 * renders class child with wrong context with server stream render
1483 * renders class child with wrong context with clean client render
1484 * renders class child with wrong context with client render on top of good server markup
1485 +* renders class child with wrong context with client render on top of bad server markup
1486 * renders stateless child with wrong context with server string render
1487 * renders stateless child with wrong context with server stream render
1488 * renders stateless child with wrong context with clean client render
1489 * renders stateless child with wrong context with client render on top of good server markup
1490 +* renders stateless child with wrong context with client render on top of bad server markup
1491 * renders with context passed through to a grandchild with server string render
1492 * renders with context passed through to a grandchild with server stream render
1493 * renders with context passed through to a grandchild with clean client render
1494 * renders with context passed through to a grandchild with client render on top of good server markup
1495 +* renders with context passed through to a grandchild with client render on top of bad server markup
1496 * renders a child context overriding a parent context with server string render
1497 * renders a child context overriding a parent context with server stream render
1498 * renders a child context overriding a parent context with clean client render
1499 * renders a child context overriding a parent context with client render on top of good server markup
1500 +* renders a child context overriding a parent context with client render on top of bad server markup
1501 * renders a child context merged with a parent context with server string render
1502 * renders a child context merged with a parent context with server stream render
1503 * renders a child context merged with a parent context with clean client render
1504 * renders a child context merged with a parent context with client render on top of good server markup
1505 +* renders a child context merged with a parent context with client render on top of bad server markup
1506 * renders with a call to componentWillMount before getChildContext with server string render
1507 * renders with a call to componentWillMount before getChildContext with server stream render
1508 * renders with a call to componentWillMount before getChildContext with clean client render
1509 * renders with a call to componentWillMount before getChildContext with client render on top of good server markup
1510 +* renders with a call to componentWillMount before getChildContext with client render on top of bad server markup
1511 * throws when rendering if getChildContext exists without childContextTypes with server string render
1512 * throws when rendering if getChildContext exists without childContextTypes with clean client render
1513 * 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
1527 * should reconnect ES6 Class to Bare Element
1528 * should reconnect Pure Component to Bare Element
1529 * should reconnect Bare Element to Bare Element
1530 +* should error reconnecting different element types
1531 +* should error reconnecting missing attributes
1532 +* should error reconnecting added attributes
1533 +* should error reconnecting different attribute values
1534 +* should error reconnecting different text
1535 * should reconnect a div with a number and string version of number
1536 +* should error reconnecting different numbers
1537 +* should error reconnecting different number from text
1538 +* should error reconnecting different text in two code blocks
1539 +* should error reconnecting missing children
1540 +* should error reconnecting added children
1541 +* should error reconnecting more children
1542 +* should error reconnecting fewer children
1543 +* should error reconnecting reordered children
1544 +* should error reconnecting a div with children separated by whitespace on the client
1545 +* should error reconnecting a div with children separated by different whitespace on the server
1546 +* should error reconnecting a div with children separated by different whitespace
1547 +* can distinguish an empty component from a dom node
1548 +* can distinguish an empty component from an empty text component
1549 +* should error reconnecting a div with different dangerouslySetInnerHTML
1550
1551 src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
1552 * updates a mounted text component in place
@@ -1427,8 +1567,10 @@ src/renderers/dom/shared/__tests__/ReactMount-test.js
1567 * should render different components in same root
1568 * should unmount and remount if the key changes
1569 * should reuse markup if rendering to the same target twice
1570 +* should warn if mounting into dirty rendered markup
1571 * should not warn if mounting into non-empty node
1572 * should warn when mounting into document.body
1573 +* should account for escaping on a checksum mismatch
1574 * should warn if render removes React-rendered children
1575 * should warn if the unmounted node was rendered by another copy of React
1576 * passes the correct callback context
@@ -1457,6 +1599,7 @@ src/renderers/dom/shared/__tests__/ReactServerRendering-test.js
1599 * should generate comment markup for component returns null
1600 * should render composite components
1601 * should only execute certain lifecycle methods
1602 +* should have the correct mounting behavior
1603 * should throw with silly args
1604 * should not put checksum and React ID on components
1605 * should not put checksum and React ID on text components
src/renderers/dom/fiber/ReactDOMFiberComponent.js
+239
@@ -46,6 +46,7 @@ if (__DEV__) {
46 } = ReactDOMUnknownPropertyHook;
47 }
48
49 +var didWarnInvalidHydration = false;
50 var didWarnShadyDOM = false;
51
52 var listenTo = ReactBrowserEventEmitter.listenTo;
@@ -69,6 +70,66 @@ if (__DEV__) {
70 validateInputPropertes(type, props);
71 validateUnknownPropertes(type, props);
72 };
73 +
74 + var warnForTextDifference = function(serverText: string, clientText: string) {
75 + if (didWarnInvalidHydration) {
76 + return;
77 + }
78 + didWarnInvalidHydration = true;
79 + warning(
80 + false,
81 + 'Text content did not match. Server: "%s" Client: "%s"',
82 + serverText,
83 + clientText,
84 + );
85 + };
86 +
87 + var warnForPropDifference = function(
88 + propName: string,
89 + serverValue: mixed,
90 + clientValue: mixed,
91 + ) {
92 + if (didWarnInvalidHydration) {
93 + return;
94 + }
95 + didWarnInvalidHydration = true;
96 + warning(
97 + false,
98 + 'Prop `%s` did not match. Server: %s Client: %s',
99 + propName,
100 + JSON.stringify(serverValue),
101 + JSON.stringify(clientValue),
102 + );
103 + };
104 +
105 + var warnForExtraAttributes = function(attributeNames: Set<string>) {
106 + if (didWarnInvalidHydration) {
107 + return;
108 + }
109 + didWarnInvalidHydration = true;
110 + var names = [];
111 + attributeNames.forEach(function(name) {
112 + names.push(name);
113 + });
114 + warning(false, 'Extra attributes from the server: %s', names);
115 + };
116 +
117 + var testDocument;
118 + // Parse the HTML and read it back to normalize the HTML string so that it
119 + // can be used for comparison.
120 + var normalizeHTML = function(parent: Element, html: string) {
121 + if (!testDocument) {
122 + testDocument = document.implementation.createHTMLDocument();
123 + }
124 + var testElement = parent.namespaceURI === HTML_NAMESPACE
125 + ? testDocument.createElement(parent.tagName)
126 + : testDocument.createElementNS(
127 + (parent.namespaceURI: any),
128 + parent.tagName,
129 + );
130 + testElement.innerHTML = html;
131 + return testElement.innerHTML;
132 + };
133 }
134
135 function ensureListeningTo(rootContainerElement, registrationName) {
@@ -766,6 +827,36 @@ var ReactDOMFiberComponent = {
827
828 assertValidProps(tag, rawProps, getCurrentFiberOwnerName);
829
830 + if (__DEV__) {
831 + var extraAttributeNames: Set<string> = new Set();
832 + var attributes = domElement.attributes;
833 + for (var i = 0; i < attributes.length; i++) {
834 + // TODO: Do we need to lower case this to get case insensitive matches?
835 + var name = attributes[i].name;
836 + switch (name) {
837 + // Built-in attributes are whitelisted
838 + // TODO: Once these are gone from the server renderer, we don't need
839 + // this whitelist aynymore.
840 + case 'data-reactroot':
841 + break;
842 + case 'data-reactid':
843 + break;
844 + case 'data-react-checksum':
845 + break;
846 + // Controlled attributes are not validated
847 + // TODO: Only ignore them on controlled tags.
848 + case 'value':
849 + break;
850 + case 'checked':
851 + break;
852 + case 'selected':
853 + break;
854 + default:
855 + extraAttributeNames.add(attributes[i].name);
856 + }
857 + }
858 + }
859 +
860 var updatePayload = null;
861 for (var propKey in rawProps) {
862 if (!rawProps.hasOwnProperty(propKey)) {
@@ -784,10 +875,16 @@ var ReactDOMFiberComponent = {
875 // TODO: Should we use domElement.firstChild.nodeValue to compare?
876 if (typeof nextProp === 'string') {
877 if (domElement.textContent !== nextProp) {
878 + if (__DEV__) {
879 + warnForTextDifference(domElement.textContent, nextProp);
880 + }
881 updatePayload = [CHILDREN, nextProp];
882 }
883 } else if (typeof nextProp === 'number') {
884 if (domElement.textContent !== '' + nextProp) {
885 + if (__DEV__) {
886 + warnForTextDifference(domElement.textContent, nextProp);
887 + }
888 updatePayload = [CHILDREN, '' + nextProp];
889 }
890 }
@@ -795,6 +892,64 @@ var ReactDOMFiberComponent = {
892 if (nextProp) {
893 ensureListeningTo(rootContainerElement, propKey);
894 }
895 + } else if (__DEV__) {
896 + // Validate that the properties correspond to their expected values.
897 + var serverValue;
898 + var propertyInfo;
899 + if (
900 + propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
901 + // Controlled attributes are not validated
902 + // TODO: Only ignore them on controlled tags.
903 + propKey === 'value' ||
904 + propKey === 'checked' ||
905 + propKey === 'selected'
906 + ) {
907 + // Noop
908 + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
909 + const rawHtml = nextProp ? nextProp[HTML] || '' : '';
910 + const serverHTML = domElement.innerHTML;
911 + const expectedHTML = normalizeHTML(domElement, rawHtml);
912 + if (expectedHTML !== serverHTML) {
913 + warnForPropDifference(propKey, serverHTML, expectedHTML);
914 + }
915 + } else if (propKey === STYLE) {
916 + // $FlowFixMe - Should be inferred as not undefined.
917 + extraAttributeNames.delete(propKey);
918 + // TOOD: Validate style sheets.
919 + } else if (
920 + isCustomComponentTag ||
921 + DOMProperty.isCustomAttribute(propKey)
922 + ) {
923 + // $FlowFixMe - Should be inferred as not undefined.
924 + extraAttributeNames.delete(propKey);
925 + serverValue = DOMPropertyOperations.getValueForAttribute(
926 + domElement,
927 + propKey,
928 + nextProp,
929 + );
930 + if (nextProp !== serverValue) {
931 + warnForPropDifference(propKey, serverValue, nextProp);
932 + }
933 + } else if ((propertyInfo = DOMProperty.properties[propKey])) {
934 + // $FlowFixMe - Should be inferred as not undefined.
935 + extraAttributeNames.delete(propertyInfo.attributeName);
936 + serverValue = DOMPropertyOperations.getValueForProperty(
937 + domElement,
938 + propKey,
939 + nextProp,
940 + );
941 + if (nextProp !== serverValue) {
942 + warnForPropDifference(propKey, serverValue, nextProp);
943 + }
944 + }
945 + }
946 + }
947 +
948 + if (__DEV__) {
949 + // $FlowFixMe - Should be inferred as not undefined.
950 + if (extraAttributeNames.size > 0) {
951 + // $FlowFixMe - Should be inferred as not undefined.
952 + warnForExtraAttributes(extraAttributeNames);
953 }
954 }
955
@@ -830,6 +985,90 @@ var ReactDOMFiberComponent = {
985 return updatePayload;
986 },
987
988 + diffHydratedText(textNode: Text, text: string): boolean {
989 + const isDifferent = textNode.nodeValue !== text;
990 + if (__DEV__) {
991 + if (isDifferent) {
992 + warnForTextDifference(textNode.nodeValue, text);
993 + }
994 + }
995 + return isDifferent;
996 + },
997 +
998 + warnForDeletedHydratableElement(
999 + parentNode: Element | Document,
1000 + child: Element,
1001 + ) {
1002 + if (__DEV__) {
1003 + if (didWarnInvalidHydration) {
1004 + return;
1005 + }
1006 + didWarnInvalidHydration = true;
1007 + warning(
1008 + false,
1009 + 'Did not expect server HTML to contain a <%s> in <%s>.',
1010 + child.nodeName.toLowerCase(),
1011 + parentNode.nodeName.toLowerCase(),
1012 + );
1013 + }
1014 + },
1015 +
1016 + warnForDeletedHydratableText(parentNode: Element | Document, child: Text) {
1017 + if (__DEV__) {
1018 + if (didWarnInvalidHydration) {
1019 + return;
1020 + }
1021 + didWarnInvalidHydration = true;
1022 + warning(
1023 + false,
1024 + 'Did not expect server HTML to contain the text node "%s" in <%s>.',
1025 + child.nodeValue,
1026 + parentNode.nodeName.toLowerCase(),
1027 + );
1028 + }
1029 + },
1030 +
1031 + warnForInsertedHydratedElement(
1032 + parentNode: Element | Document,
1033 + tag: string,
1034 + props: Object,
1035 + ) {
1036 + if (__DEV__) {
1037 + if (didWarnInvalidHydration) {
1038 + return;
1039 + }
1040 + didWarnInvalidHydration = true;
1041 + warning(
1042 + false,
1043 + 'Did not find a matching <%s> in <%s>.',
1044 + tag,
1045 + parentNode.nodeName.toLowerCase(),
1046 + );
1047 + }
1048 + },
1049 +
1050 + warnForInsertedHydratedText(parentNode: Element | Document, text: string) {
1051 + if (__DEV__) {
1052 + if (text === '') {
1053 + // We expect to insert empty text nodes since they're not represented in
1054 + // the HTML.
1055 + // TODO: Remove this special case if we can just avoid inserting empty
1056 + // text nodes.
1057 + return;
1058 + }
1059 + if (didWarnInvalidHydration) {
1060 + return;
1061 + }
1062 + didWarnInvalidHydration = true;
1063 + warning(
1064 + false,
1065 + 'Did not find a matching text node for "%s" in <%s>.',
1066 + text,
1067 + parentNode.nodeName.toLowerCase(),
1068 + );
1069 + }
1070 + },
1071 +
1072 restoreControlledState(
1073 domElement: Element,
1074 tag: string,
src/renderers/dom/fiber/ReactDOMFiberEntry.js
+33 -1
@@ -51,6 +51,11 @@ var {
51 diffProperties,
52 updateProperties,
53 diffHydratedProperties,
54 + diffHydratedText,
55 + warnForDeletedHydratableElement,
56 + warnForDeletedHydratableText,
57 + warnForInsertedHydratedElement,
58 + warnForInsertedHydratedText,
59 } = ReactDOMFiberComponent;
60 var {precacheFiberNode, updateFiberProps} = ReactDOMComponentTree;
61
@@ -314,6 +319,7 @@ var DOMRenderer = ReactFiberReconciler({
319
320 shouldSetTextContent(type: string, props: Props): boolean {
321 return (
322 + type === 'textarea' ||
323 typeof props.children === 'string' ||
324 typeof props.children === 'number' ||
325 (typeof props.dangerouslySetInnerHTML === 'object' &&
@@ -475,7 +481,33 @@ var DOMRenderer = ReactFiberReconciler({
481 internalInstanceHandle: Object,
482 ): boolean {
483 precacheFiberNode(internalInstanceHandle, textInstance);
478 - return textInstance.nodeValue !== text;
484 + return diffHydratedText(textInstance, text);
485 + },
486 +
487 + didNotHydrateInstance(
488 + parentInstance: Instance | Container,
489 + instance: Instance | TextInstance,
490 + ) {
491 + if (instance.nodeType === 1) {
492 + warnForDeletedHydratableElement(parentInstance, (instance: any));
493 + } else {
494 + warnForDeletedHydratableText(parentInstance, (instance: any));
495 + }
496 + },
497 +
498 + didNotFindHydratableInstance(
499 + parentInstance: Instance | Container,
500 + type: string,
501 + props: Props,
502 + ) {
503 + warnForInsertedHydratedElement(parentInstance, type, props);
504 + },
505 +
506 + didNotFindHydratableTextInstance(
507 + parentInstance: Instance | Container,
508 + text: string,
509 + ) {
510 + warnForInsertedHydratedText(parentInstance, text);
511 },
512
513 scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
src/renderers/dom/shared/DOMPropertyOperations.js
+84
@@ -128,6 +128,90 @@ var DOMPropertyOperations = {
128 return name + '=' + quoteAttributeValueForBrowser(value);
129 },
130
131 + /**
132 + * Get the value for a property on a node. Only used in DEV for SSR validation.
133 + * The "expected" argument is used as a hint of what the expected value is.
134 + * Some properties have multiple equivalent values.
135 + */
136 + getValueForProperty: function(node, name, expected) {
137 + if (__DEV__) {
138 + var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
139 + ? DOMProperty.properties[name]
140 + : null;
141 + if (propertyInfo) {
142 + var mutationMethod = propertyInfo.mutationMethod;
143 + if (mutationMethod || propertyInfo.mustUseProperty) {
144 + return node[propertyInfo.propertyName];
145 + } else {
146 + var attributeName = propertyInfo.attributeName;
147 +
148 + var stringValue = null;
149 +
150 + if (propertyInfo.hasOverloadedBooleanValue) {
151 + if (node.hasAttribute(attributeName)) {
152 + var value = node.getAttribute(attributeName);
153 + if (value === '') {
154 + return true;
155 + }
156 + return value;
157 + }
158 + } else if (node.hasAttribute(attributeName)) {
159 + if (shouldIgnoreValue(propertyInfo, expected)) {
160 + // We had an attribute but shouldn't have had one, so read it
161 + // for the error message.
162 + return node.getAttribute(attributeName);
163 + }
164 + if (propertyInfo.hasBooleanValue) {
165 + // If this was a boolean, it doesn't matter what the value is
166 + // the fact that we have it is the same as the expected.
167 + return expected;
168 + }
169 + // Even if this property uses a namespace we use getAttribute
170 + // because we assume its namespaced name is the same as our config.
171 + // To use getAttributeNS we need the local name which we don't have
172 + // in our config atm.
173 + stringValue = node.getAttribute(attributeName);
174 + }
175 +
176 + if (shouldIgnoreValue(propertyInfo, expected)) {
177 + return stringValue === null ? expected : stringValue;
178 + } else if (stringValue === '' + expected) {
179 + return expected;
180 + } else {
181 + return stringValue;
182 + }
183 + }
184 + } else if (DOMProperty.isCustomAttribute(name)) {
185 + return DOMPropertyOperations.diffValueForAttribute(
186 + node,
187 + name,
188 + expected,
189 + );
190 + }
191 + }
192 + },
193 +
194 + /**
195 + * Get the value for a attribute on a node. Only used in DEV for SSR validation.
196 + * The third argument is used as a hint of what the expected value is. Some
197 + * attributes have multiple equivalent values.
198 + */
199 + getValueForAttribute: function(node, name, expected) {
200 + if (__DEV__) {
201 + if (!isAttributeNameSafe(name)) {
202 + return;
203 + }
204 + if (!node.hasAttribute(name)) {
205 + return expected === undefined ? undefined : null;
206 + }
207 + var value = node.getAttribute(name);
208 + if (value === '' + expected) {
209 + return expected;
210 + }
211 + return value;
212 + }
213 + },
214 +
215 /**
216 * Sets the value for a property on a node.
217 *
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
+6 -1
@@ -2142,7 +2142,12 @@ describe('ReactDOMServerIntegration', () => {
2142 ));
2143
2144 it('can distinguish an empty component from an empty text component', () =>
2145 - expectMarkupMismatch(<div><EmptyComponent /></div>, <div>{''}</div>));
2145 + (ReactDOMFeatureFlags.useFiber
2146 + ? expectMarkupMatch
2147 + : expectMarkupMismatch)(
2148 + <div><EmptyComponent /></div>,
2149 + <div>{''}</div>,
2150 + ));
2151 });
2152
2153 // Markup Mismatches: misc
src/renderers/dom/shared/__tests__/ReactMount-test.js
+13 -4
@@ -153,6 +153,8 @@ describe('ReactMount', () => {
153 ReactDOM.render(<div />, container);
154 expectDev(console.error.calls.count()).toBe(1);
155
156 + ReactDOM.unmountComponentAtNode(container);
157 +
158 container.innerHTML = ' ' + ReactDOMServer.renderToString(<div />);
159
160 ReactDOM.render(<div />, container);
@@ -194,10 +196,17 @@ describe('ReactMount', () => {
196 div,
197 );
198 expectDev(console.error.calls.count()).toBe(1);
197 - expectDev(console.error.calls.argsFor(0)[0]).toContain(
198 - ' (client) nbsp entity: &nbsp; client text</div>\n' +
199 - ' (server) nbsp entity: &nbsp; server text</div>',
200 - );
199 + if (ReactDOMFeatureFlags.useFiber) {
200 + expectDev(console.error.calls.argsFor(0)[0]).toContain(
201 + 'Server: "This markup contains an nbsp entity:   server text" ' +
202 + 'Client: "This markup contains an nbsp entity:   client text"',
203 + );
204 + } else {
205 + expectDev(console.error.calls.argsFor(0)[0]).toContain(
206 + ' (client) nbsp entity: &nbsp; client text</div>\n' +
207 + ' (server) nbsp entity: &nbsp; server text</div>',
208 + );
209 + }
210 });
211
212 if (WebComponents !== undefined) {
src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js
+5
@@ -207,8 +207,13 @@ describe('rendering React components at document', () => {
207 var testDocument = getTestDocument(markup);
208
209 if (ReactDOMFeatureFlags.useFiber) {
210 + spyOn(console, 'error');
211 ReactDOM.render(<Component text="Hello world" />, testDocument);
212 expect(testDocument.body.innerHTML).toBe('Hello world');
213 + expectDev(console.error.calls.count()).toBe(1);
214 + expectDev(console.error.calls.argsFor(0)[0]).toContain(
215 + 'Warning: Text content did not match.',
216 + );
217 } else {
218 expect(function() {
219 // Notice the text is different!
src/renderers/shared/fiber/ReactFiberHydrationContext.js
+52 -3
@@ -42,6 +42,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
42 getFirstHydratableChild,
43 hydrateInstance,
44 hydrateTextInstance,
45 + didNotHydrateInstance,
46 + didNotFindHydratableInstance,
47 + didNotFindHydratableTextInstance,
48 } = config;
49
50 // If this doesn't have hydration mode.
@@ -51,7 +54,10 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
54 getNextHydratableSibling &&
55 getFirstHydratableChild &&
56 hydrateInstance &&
54 - hydrateTextInstance)
57 + hydrateTextInstance &&
58 + didNotHydrateInstance &&
59 + didNotFindHydratableInstance &&
60 + didNotFindHydratableTextInstance)
61 ) {
62 return {
63 enterHydrationState() {
@@ -86,6 +92,17 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
92 }
93
94 function deleteHydratableInstance(returnFiber: Fiber, instance: I | TI) {
95 + if (__DEV__) {
96 + switch (returnFiber.tag) {
97 + case HostRoot:
98 + didNotHydrateInstance(returnFiber.stateNode.containerInfo, instance);
99 + break;
100 + case HostComponent:
101 + didNotHydrateInstance(returnFiber.stateNode, instance);
102 + break;
103 + }
104 + }
105 +
106 const childToDelete = createFiberFromHostInstanceForDeletion();
107 childToDelete.stateNode = instance;
108 childToDelete.return = returnFiber;
@@ -104,6 +121,38 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
121 }
122 }
123
124 + function insertNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) {
125 + fiber.effectTag |= Placement;
126 + if (__DEV__) {
127 + var parentInstance;
128 + switch (returnFiber.tag) {
129 + // TODO: Currently we don't warn for insertions into the root because
130 + // we always insert into the root in the non-hydrating case. We just
131 + // delete the existing content. Reenable this once we have a better
132 + // strategy for determining if we're hydrating or not.
133 + // case HostRoot:
134 + // parentInstance = returnFiber.stateNode.containerInfo;
135 + // break;
136 + case HostComponent:
137 + parentInstance = returnFiber.stateNode;
138 + break;
139 + default:
140 + return;
141 + }
142 + switch (fiber.tag) {
143 + case HostComponent:
144 + const type = fiber.type;
145 + const props = fiber.pendingProps;
146 + didNotFindHydratableInstance(parentInstance, type, props);
147 + break;
148 + case HostText:
149 + const text = fiber.pendingProps;
150 + didNotFindHydratableTextInstance(parentInstance, text);
151 + break;
152 + }
153 + }
154 + }
155 +
156 function canHydrate(fiber, nextInstance) {
157 switch (fiber.tag) {
158 case HostComponent: {
@@ -127,7 +176,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
176 let nextInstance = nextHydratableInstance;
177 if (!nextInstance) {
178 // Nothing to hydrate. Make it an insertion.
130 - fiber.effectTag |= Placement;
179 + insertNonHydratedInstance((hydrationParentFiber: any), fiber);
180 isHydrating = false;
181 hydrationParentFiber = fiber;
182 return;
@@ -139,7 +188,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
188 nextInstance = getNextHydratableSibling(nextInstance);
189 if (!nextInstance || !canHydrate(fiber, nextInstance)) {
190 // Nothing to hydrate. Make it an insertion.
142 - fiber.effectTag |= Placement;
191 + insertNonHydratedInstance((hydrationParentFiber: any), fiber);
192 isHydrating = false;
193 hydrationParentFiber = fiber;
194 return;
src/renderers/shared/fiber/ReactFiberReconciler.js
+10
@@ -138,6 +138,16 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
138 text: string,
139 internalInstanceHandle: OpaqueHandle,
140 ) => boolean,
141 + didNotHydrateInstance?: (parentInstance: I | C, instance: I | TI) => void,
142 + didNotFindHydratableInstance?: (
143 + parentInstance: I | C,
144 + type: T,
145 + props: P,
146 + ) => void,
147 + didNotFindHydratableTextInstance?: (
148 + parentInstance: I | C,
149 + text: string,
150 + ) => void,
151
152 useSyncScheduling?: boolean,
153 };