@@ -157,6 +157,8 @@ describe('ReactMount', () => {
157157 } ) ;
158158
159159 it ( 'should warn when a hydrated element has inner text mismatch' , ( ) => {
160+ // See fixtures/ssr: ssr-warnForTextDifference
161+
160162 class Component extends React . Component {
161163 render ( ) {
162164 return this . props . children ;
@@ -187,7 +189,69 @@ describe('ReactMount', () => {
187189 ) ;
188190 } ) ;
189191
192+ it ( 'should warn when hydrating a text node over a mismatching text node' , ( ) => {
193+ // See fixtures/ssr: ssr-warnForTextDifference-warnForUnmatchedText-didNotMatchHydratedContainerTextInstance
194+
195+ const div = document . createElement ( 'div' ) ;
196+ const markup = ReactDOMServer . renderToString ( 'server text' ) ;
197+ div . innerHTML = markup ;
198+
199+ expect ( ( ) => ReactDOM . hydrate ( 'client text' , div ) ) . toWarnDev (
200+ 'Text content did not match. ' +
201+ 'Server: "server text" ' +
202+ 'Client: "client text"' ,
203+ ) ;
204+ } ) ;
205+
206+ it ( 'should warn when a hydrated element has first text match but second text mismatch' , ( ) => {
207+ // See fixtures/ssr: ssr-warnForTextDifference-warnForUnmatchedText-didNotMatchHydratedTextInstance
208+
209+ class Component extends React . Component {
210+ render ( ) {
211+ return this . props . children ;
212+ }
213+ }
214+
215+ const serverRandom = Math . random ( ) ;
216+ const clientRandom = Math . random ( ) ;
217+
218+ const div = document . createElement ( 'div' ) ;
219+ const markup = ReactDOMServer . renderToString (
220+ < Component >
221+ < em >
222+ { 'SSRMismatchTest static text and ' }
223+ { 'server random text ' + serverRandom }
224+ </ em >
225+ </ Component > ,
226+ ) ;
227+ div . innerHTML = markup ;
228+
229+ expect ( ( ) =>
230+ ReactDOM . hydrate (
231+ < Component >
232+ < em >
233+ { 'SSRMismatchTest static text and ' }
234+ { 'client random text ' + clientRandom }
235+ </ em >
236+ </ Component > ,
237+ div ,
238+ ) ,
239+ ) . toWarnDev (
240+ 'Text content did not match. ' +
241+ 'Server: "server random text ' +
242+ serverRandom +
243+ '" ' +
244+ 'Client: "client random text ' +
245+ clientRandom +
246+ '"\n' +
247+ ' in em (at **)\n' +
248+ ' in Component (at **)' ,
249+ ) ;
250+ } ) ;
251+
190252 it ( 'should warn when a hydrated element has children mismatch' , ( ) => {
253+ // See fixtures/ssr: ssr-warnForInsertedHydratedText-didNotFindHydratableTextInstance
254+
191255 class Component extends React . Component {
192256 render ( ) {
193257 return this . props . children ;
@@ -242,43 +306,275 @@ describe('ReactMount', () => {
242306 ) ;
243307 } ) ;
244308
245- it ( 'should warn when a hydrated element has extra props' , ( ) => {
309+ it ( 'should warn when a hydrated element has extra props with non-null values' , ( ) => {
310+ // See fixtures/ssr: ssr-warnForPropDifference
311+
246312 const div = document . createElement ( 'div' ) ;
247- const markup = ReactDOMServer . renderToString ( < div /> ) ;
313+ const markup = ReactDOMServer . renderToString (
314+ < div >
315+ < em > SSRMismatchTest default text</ em >
316+ </ div > ,
317+ ) ;
248318 div . innerHTML = markup ;
249319
250320 expect ( ( ) =>
251321 ReactDOM . hydrate (
252- < div data-ssr-prop-mismatch = { true } data-ssr-prop-mismatch-2 = { true } /> ,
322+ < div data-ssr-extra-prop = { true } data-ssr-extra-prop-2 = { true } >
323+ < em > SSRMismatchTest default text</ em >
324+ </ div > ,
253325 div ,
254326 ) ,
255327 ) . toWarnDev (
256- 'Prop `data-ssr-prop-mismatch ` did not match. ' +
328+ 'Prop `data-ssr-extra-prop ` did not match. ' +
257329 'Server: "null" ' +
258330 'Client: "true"\n' +
259331 ' in div (at **)' ,
260332 ) ;
261333 } ) ;
262334
263- it ( 'should not warn when a hydrated element has an extra prop explicitly set to null' , ( ) => {
335+ it ( 'should not warn when a hydrated element has extra props explicitly set to null' , ( ) => {
336+ // See fixtures/ssr: ssr-warnForPropDifference-null-no-warning
337+
264338 const div = document . createElement ( 'div' ) ;
265- const markup = ReactDOMServer . renderToString ( < div /> ) ;
339+ const markup = ReactDOMServer . renderToString (
340+ < div >
341+ < em > SSRMismatchTest default text</ em >
342+ </ div > ,
343+ ) ;
266344 div . innerHTML = markup ;
267345
268346 expect ( ( ) =>
269- ReactDOM . hydrate ( < div data-ssr-prop-mismatch = { null } /> , div ) ,
347+ ReactDOM . hydrate (
348+ < div data-ssr-extra-prop = { null } data-ssr-extra-prop-2 = { null } >
349+ < em > SSRMismatchTest default text</ em >
350+ </ div > ,
351+ div ,
352+ ) ,
270353 ) . toWarnDev ( [ ] ) ;
271354 } ) ;
272355
273356 it ( 'should warn when a server element has extra props' , ( ) => {
357+ // See fixtures/ssr: ssr-warnForExtraAttributes
358+
359+ const div = document . createElement ( 'div' ) ;
360+ const markup = ReactDOMServer . renderToString (
361+ < div data-ssr-extra-prop = { true } data-ssr-extra-prop-2 = { true } >
362+ < em > SSRMismatchTest default text</ em >
363+ </ div > ,
364+ ) ;
365+ div . innerHTML = markup ;
366+
367+ expect ( ( ) =>
368+ ReactDOM . hydrate (
369+ < div >
370+ < em > SSRMismatchTest default text</ em >
371+ </ div > ,
372+ div ,
373+ ) ,
374+ ) . toWarnDev (
375+ 'Extra attributes from the server: data-ssr-extra-prop,data-ssr-extra-prop-2\n' +
376+ ' in div (at **)' ,
377+ ) ;
378+ } ) ;
379+
380+ it ( 'should warn when a browser element has an event handler which is set to false' , ( ) => {
381+ // See fixtures/ssr: ssr-warnForInvalidEventListener-false
382+
383+ const div = document . createElement ( 'div' ) ;
384+ const markup = ReactDOMServer . renderToString ( < div onClick = { ( ) => { } } /> ) ;
385+ div . innerHTML = markup ;
386+
387+ expect ( ( ) => ReactDOM . hydrate ( < div onClick = { false } /> , div ) ) . toWarnDev (
388+ 'Expected `onClick` listener to be a function, instead got `false`.\n\n' +
389+ 'If you used to conditionally omit it with onClick={condition && value}, ' +
390+ 'pass onClick={condition ? value : undefined} instead.\n' +
391+ ' in div (at **)' ,
392+ ) ;
393+ } ) ;
394+
395+ it ( 'should warn when a browser element has an event handler which is set to a non-function, non-false value' , ( ) => {
396+ // See fixtures/ssr: ssr-warnForInvalidEventListener-typeof
397+
398+ const div = document . createElement ( 'div' ) ;
399+ const markup = ReactDOMServer . renderToString ( < div onClick = { ( ) => { } } /> ) ;
400+ div . innerHTML = markup ;
401+
402+ expect ( ( ) => ReactDOM . hydrate ( < div onClick = { 'a string' } /> , div ) ) . toWarnDev (
403+ 'Expected `onClick` listener to be a function, instead got a value of `string` type.\n' +
404+ ' in div (at **)' ,
405+ ) ;
406+ } ) ;
407+
408+ it ( 'should warn when hydrate removes an element from a server-rendered sequence in the root container' , ( ) => {
409+ // See fixtures/ssr: ssr-warnForDeletedHydratableElement-didNotHydrateContainerInstance
410+
411+ const div = document . createElement ( 'div' ) ;
412+ const markup =
413+ 'SSRMismatchTest first text' +
414+ '<br />' +
415+ '<br />' +
416+ 'SSRMismatchTest second text' ;
417+ div . innerHTML = markup ;
418+
419+ expect ( ( ) =>
420+ ReactDOM . hydrate (
421+ [
422+ 'SSRMismatchTest first text' ,
423+ < br key = { 1 } /> ,
424+ 'SSRMismatchTest second text' ,
425+ ] ,
426+ div ,
427+ ) ,
428+ ) . toWarnDev ( 'Did not expect server HTML to contain a <br> in <div>.' ) ;
429+ } ) ;
430+
431+ it ( 'should warn when hydrate removes an element from a server-rendered sequence' , ( ) => {
432+ // See fixtures/ssr: ssr-warnForDeletedHydratableElement-didNotHydrateInstance
433+
434+ const div = document . createElement ( 'div' ) ;
435+ const markup = ReactDOMServer . renderToString (
436+ < div >
437+ < div />
438+ < span />
439+ </ div > ,
440+ ) ;
441+ div . innerHTML = markup ;
442+
443+ expect ( ( ) =>
444+ ReactDOM . hydrate (
445+ < div >
446+ < span />
447+ </ div > ,
448+ div ,
449+ ) ,
450+ ) . toWarnDev (
451+ 'Did not expect server HTML to contain a <div> in <div>.\n' +
452+ ' in span (at **)\n' +
453+ ' in div (at **)' ,
454+ ) ;
455+ } ) ;
456+
457+ it ( 'should warn when hydrate removes a text node from a server-rendered sequence in the root container' , ( ) => {
458+ // See fixtures/ssr: ssr-warnForDeletedHydratableText-didNotHydrateContainerInstance
459+
460+ const div = document . createElement ( 'div' ) ;
461+ const markup =
462+ 'SSRMismatchTest server text' + '<br />' + 'SSRMismatchTest default text' ;
463+ div . innerHTML = markup ;
464+
465+ expect ( ( ) =>
466+ ReactDOM . hydrate ( [ < br key = { 1 } /> , 'SSRMismatchTest default text' ] , div ) ,
467+ ) . toWarnDev (
468+ 'Did not expect server HTML to contain the text node "SSRMismatchTest server text" in <div>.\n' +
469+ ' in br (at **)' ,
470+ ) ;
471+ } ) ;
472+
473+ it ( 'should warn when hydrate removes a text node from a server-rendered sequence' , ( ) => {
474+ // See fixtures/ssr: ssr-warnForDeletedHydratableText-didNotHydrateInstance
475+
476+ const div = document . createElement ( 'div' ) ;
477+ const markup = ReactDOMServer . renderToString (
478+ < div >
479+ SSRMismatchTest server text
480+ < span />
481+ </ div > ,
482+ ) ;
483+ div . innerHTML = markup ;
484+
485+ expect ( ( ) =>
486+ ReactDOM . hydrate (
487+ < div >
488+ < span />
489+ </ div > ,
490+ div ,
491+ ) ,
492+ ) . toWarnDev (
493+ 'Did not expect server HTML to contain the text node "SSRMismatchTest server text" in <div>.\n' +
494+ ' in span (at **)\n' +
495+ ' in div (at **)' ,
496+ ) ;
497+ } ) ;
498+
499+ it ( 'should warn when hydrate inserts an element to replace a text node in the root container' , ( ) => {
500+ // See fixtures/ssr: ssr-warnForInsertedHydratedElement-didNotFindHydratableContainerInstance
501+
502+ const div = document . createElement ( 'div' ) ;
503+ const markup = 'SSRMismatchTest default text' ;
504+ div . innerHTML = markup ;
505+
506+ expect ( ( ) =>
507+ ReactDOM . hydrate ( < span > SSRMismatchTest default text</ span > , div ) ,
508+ ) . toWarnDev (
509+ 'Expected server HTML to contain a matching <span> in <div>.\n' +
510+ ' in span (at **)' ,
511+ ) ;
512+ } ) ;
513+
514+ it ( 'should warn when hydrate inserts an element to replace a different element' , ( ) => {
515+ // See fixtures/ssr: ssr-warnForInsertedHydratedElement-didNotFindHydratableInstance
516+
517+ const div = document . createElement ( 'div' ) ;
518+ const markup = ReactDOMServer . renderToString (
519+ < div >
520+ < em > SSRMismatchTest default text</ em >
521+ </ div > ,
522+ ) ;
523+ div . innerHTML = markup ;
524+
525+ expect ( ( ) =>
526+ ReactDOM . hydrate (
527+ < div >
528+ < p > SSRMismatchTest default text</ p >
529+ </ div > ,
530+ div ,
531+ ) ,
532+ ) . toWarnDev (
533+ 'Expected server HTML to contain a matching <p> in <div>.\n' +
534+ ' in p (at **)\n' +
535+ ' in div (at **)' ,
536+ ) ;
537+ } ) ;
538+
539+ it ( 'should warn when hydrate inserts a text node to replace an element in the root container' , ( ) => {
540+ // See fixtures/ssr: ssr-warnForInsertedHydratedText-didNotFindHydratableContainerTextInstance
541+
274542 const div = document . createElement ( 'div' ) ;
275543 const markup = ReactDOMServer . renderToString (
276- < div data-ssr-prop-extra = { true } data-ssr-prop-extra-2 = { true } / >,
544+ < span > SSRMismatchTest default text </ span > ,
277545 ) ;
278546 div . innerHTML = markup ;
279547
280- expect ( ( ) => ReactDOM . hydrate ( < div /> , div ) ) . toWarnDev (
281- 'Extra attributes from the server: data-ssr-prop-extra,data-ssr-prop-extra-2\n' +
548+ expect ( ( ) =>
549+ ReactDOM . hydrate ( 'SSRMismatchTest default text' , div ) ,
550+ ) . toWarnDev (
551+ 'Expected server HTML to contain a matching text node for "SSRMismatchTest default text" in <div>.' ,
552+ ) ;
553+ } ) ;
554+
555+ it ( 'should warn when hydrate inserts a text node between matching elements' , ( ) => {
556+ // See fixtures/ssr: ssr-warnForInsertedHydratedText-didNotFindHydratableTextInstance
557+
558+ const div = document . createElement ( 'div' ) ;
559+ const markup = ReactDOMServer . renderToString (
560+ < div >
561+ < span />
562+ < span />
563+ </ div > ,
564+ ) ;
565+ div . innerHTML = markup ;
566+
567+ expect ( ( ) =>
568+ ReactDOM . hydrate (
569+ < div >
570+ < span />
571+ SSRMismatchTest client text
572+ < span />
573+ </ div > ,
574+ div ,
575+ ) ,
576+ ) . toWarnDev (
577+ 'Expected server HTML to contain a matching text node for "SSRMismatchTest client text" in <div>.\n' +
282578 ' in div (at **)' ,
283579 ) ;
284580 } ) ;
0 commit comments