@@ -47,6 +47,15 @@ let waitForPaint;
47
47
let clientAct ;
48
48
let streamingContainer ;
49
49
50
+ function normalizeError ( msg ) {
51
+ // Take the first sentence to make it easier to assert on.
52
+ const idx = msg . indexOf ( '.' ) ;
53
+ if ( idx > - 1 ) {
54
+ return msg . slice ( 0 , idx + 1 ) ;
55
+ }
56
+ return msg ;
57
+ }
58
+
50
59
describe ( 'ReactDOMFizzServer' , ( ) => {
51
60
beforeEach ( ( ) => {
52
61
jest . resetModules ( ) ;
@@ -2391,26 +2400,22 @@ describe('ReactDOMFizzServer', () => {
2391
2400
2392
2401
ReactDOMClient . hydrateRoot ( container , < App /> , {
2393
2402
onRecoverableError ( error ) {
2394
- Scheduler . log ( 'Log recoverable error: ' + error . message ) ;
2403
+ Scheduler . log (
2404
+ 'Log recoverable error: ' + normalizeError ( error . message ) ,
2405
+ ) ;
2395
2406
} ,
2396
2407
} ) ;
2397
2408
2398
2409
await expect ( async ( ) => {
2399
2410
// The first paint switches to client rendering due to mismatch
2400
2411
await waitForPaint ( [
2401
2412
'client' ,
2402
- 'Log recoverable error: Hydration failed because the initial ' +
2403
- 'UI does not match what was rendered on the server.' ,
2404
- 'Log recoverable error: There was an error while hydrating. ' +
2405
- 'Because the error happened outside of a Suspense boundary, the ' +
2406
- 'entire root will switch to client rendering.' ,
2413
+ "Log recoverable error: Hydration failed because the server rendered HTML didn't match the client." ,
2414
+ 'Log recoverable error: There was an error while hydrating.' ,
2407
2415
] ) ;
2408
2416
} ) . toErrorDev (
2409
2417
[
2410
2418
'Warning: An error occurred during hydration. The server HTML was replaced with client content.' ,
2411
- 'Warning: Expected server HTML to contain a matching <div> in the root.\n' +
2412
- ' in div (at **)\n' +
2413
- ' in App (at **)' ,
2414
2419
] ,
2415
2420
{ withoutStack : 1 } ,
2416
2421
) ;
@@ -2474,7 +2479,9 @@ describe('ReactDOMFizzServer', () => {
2474
2479
2475
2480
ReactDOMClient . hydrateRoot ( container , < App /> , {
2476
2481
onRecoverableError ( error ) {
2477
- Scheduler . log ( 'Log recoverable error: ' + error . message ) ;
2482
+ Scheduler . log (
2483
+ 'Log recoverable error: ' + normalizeError ( error . message ) ,
2484
+ ) ;
2478
2485
} ,
2479
2486
} ) ;
2480
2487
@@ -2483,18 +2490,12 @@ describe('ReactDOMFizzServer', () => {
2483
2490
// The first paint switches to client rendering due to mismatch
2484
2491
await waitForPaint ( [
2485
2492
'client' ,
2486
- 'Log recoverable error: Hydration failed because the initial ' +
2487
- 'UI does not match what was rendered on the server.' ,
2488
- 'Log recoverable error: There was an error while hydrating. ' +
2489
- 'Because the error happened outside of a Suspense boundary, the ' +
2490
- 'entire root will switch to client rendering.' ,
2493
+ "Log recoverable error: Hydration failed because the server rendered HTML didn't match the client." ,
2494
+ 'Log recoverable error: There was an error while hydrating.' ,
2491
2495
] ) ;
2492
2496
} ) . toErrorDev (
2493
2497
[
2494
2498
'Warning: An error occurred during hydration. The server HTML was replaced with client content' ,
2495
- 'Warning: Expected server HTML to contain a matching <div> in the root.\n' +
2496
- ' in div (at **)\n' +
2497
- ' in App (at **)' ,
2498
2499
] ,
2499
2500
{ withoutStack : 1 } ,
2500
2501
) ;
@@ -2557,7 +2558,7 @@ describe('ReactDOMFizzServer', () => {
2557
2558
isClient = true ;
2558
2559
ReactDOMClient . hydrateRoot ( container , < App /> , {
2559
2560
onRecoverableError ( error ) {
2560
- Scheduler . log ( error . message ) ;
2561
+ Scheduler . log ( normalizeError ( error . message ) ) ;
2561
2562
} ,
2562
2563
} ) ;
2563
2564
@@ -2567,9 +2568,7 @@ describe('ReactDOMFizzServer', () => {
2567
2568
await waitForAll ( [
2568
2569
'Yay!' ,
2569
2570
'Hydration error' ,
2570
- 'There was an error while hydrating. Because the error happened ' +
2571
- 'outside of a Suspense boundary, the entire root will switch ' +
2572
- 'to client rendering.' ,
2571
+ 'There was an error while hydrating.' ,
2573
2572
] ) ;
2574
2573
} ) . toErrorDev (
2575
2574
'An error occurred during hydration. The server HTML was replaced' ,
@@ -2739,7 +2738,7 @@ describe('ReactDOMFizzServer', () => {
2739
2738
isClient = true ;
2740
2739
ReactDOMClient . hydrateRoot ( container , < App /> , {
2741
2740
onRecoverableError ( error ) {
2742
- Scheduler . log ( error . message ) ;
2741
+ Scheduler . log ( normalizeError ( error . message ) ) ;
2743
2742
} ,
2744
2743
} ) ;
2745
2744
@@ -2748,7 +2747,7 @@ describe('ReactDOMFizzServer', () => {
2748
2747
await waitForAll ( [
2749
2748
'Yay!' ,
2750
2749
'Hydration error' ,
2751
- 'There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
2750
+ 'There was an error while hydrating this Suspense boundary.' ,
2752
2751
] ) ;
2753
2752
expect ( getVisibleChildren ( container ) ) . toEqual (
2754
2753
< div >
@@ -3194,16 +3193,15 @@ describe('ReactDOMFizzServer', () => {
3194
3193
isClient = true ;
3195
3194
ReactDOMClient . hydrateRoot ( container , < App /> , {
3196
3195
onRecoverableError ( error ) {
3197
- Scheduler . log ( error . message ) ;
3196
+ Scheduler . log ( normalizeError ( error . message ) ) ;
3198
3197
} ,
3199
3198
} ) ;
3200
3199
3201
3200
// An error logged but instead of surfacing it to the UI, we switched
3202
3201
// to client rendering.
3203
3202
await waitForAll ( [
3204
3203
'Hydration error' ,
3205
- 'There was an error while hydrating this Suspense boundary. Switched ' +
3206
- 'to client rendering.' ,
3204
+ 'There was an error while hydrating this Suspense boundary.' ,
3207
3205
] ) ;
3208
3206
expect ( getVisibleChildren ( container ) ) . toEqual (
3209
3207
< div >
@@ -3263,7 +3261,9 @@ describe('ReactDOMFizzServer', () => {
3263
3261
3264
3262
const root = ReactDOMClient . createRoot ( container , {
3265
3263
onRecoverableError ( error ) {
3266
- Scheduler . log ( 'Logged a recoverable error: ' + error . message ) ;
3264
+ Scheduler . log (
3265
+ 'Logged a recoverable error: ' + normalizeError ( error . message ) ,
3266
+ ) ;
3267
3267
} ,
3268
3268
} ) ;
3269
3269
React . startTransition ( ( ) => {
@@ -3339,7 +3339,9 @@ describe('ReactDOMFizzServer', () => {
3339
3339
isClient = true ;
3340
3340
ReactDOMClient . hydrateRoot ( container , < App /> , {
3341
3341
onRecoverableError ( error ) {
3342
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
3342
+ Scheduler . log (
3343
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
3344
+ ) ;
3343
3345
} ,
3344
3346
} ) ;
3345
3347
@@ -3349,11 +3351,11 @@ describe('ReactDOMFizzServer', () => {
3349
3351
3350
3352
'Logged recoverable error: Hydration error' ,
3351
3353
'Logged recoverable error: There was an error while hydrating this ' +
3352
- 'Suspense boundary. Switched to client rendering. ' ,
3354
+ 'Suspense boundary.' ,
3353
3355
3354
3356
'Logged recoverable error: Hydration error' ,
3355
3357
'Logged recoverable error: There was an error while hydrating this ' +
3356
- 'Suspense boundary. Switched to client rendering. ' ,
3358
+ 'Suspense boundary.' ,
3357
3359
] ) ;
3358
3360
} ) ;
3359
3361
@@ -4395,7 +4397,9 @@ describe('ReactDOMFizzServer', () => {
4395
4397
const [ ClientApp , clientResolve ] = makeApp ( ) ;
4396
4398
ReactDOMClient . hydrateRoot ( container , < ClientApp /> , {
4397
4399
onRecoverableError ( error ) {
4398
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4400
+ Scheduler . log (
4401
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4402
+ ) ;
4399
4403
} ,
4400
4404
} ) ;
4401
4405
await waitForAll ( [ ] ) ;
@@ -4471,7 +4475,9 @@ describe('ReactDOMFizzServer', () => {
4471
4475
const [ ClientApp , clientResolve ] = makeApp ( ) ;
4472
4476
ReactDOMClient . hydrateRoot ( container , < ClientApp text = "replaced" /> , {
4473
4477
onRecoverableError ( error ) {
4474
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4478
+ Scheduler . log (
4479
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4480
+ ) ;
4475
4481
} ,
4476
4482
} ) ;
4477
4483
await waitForAll ( [ ] ) ;
@@ -4486,14 +4492,10 @@ describe('ReactDOMFizzServer', () => {
4486
4492
// Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring
4487
4493
// client-side rendering.
4488
4494
await clientResolve ( ) ;
4489
- await expect ( async ( ) => {
4490
- await waitForAll ( [
4491
- 'Logged recoverable error: Text content does not match server-rendered HTML.' ,
4492
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.' ,
4493
- ] ) ;
4494
- } ) . toErrorDev (
4495
- 'Warning: Text content did not match. Server: "initial" Client: "replaced' ,
4496
- ) ;
4495
+ await waitForAll ( [
4496
+ "Logged recoverable error: Hydration failed because the server rendered HTML didn't match the client." ,
4497
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4498
+ ] ) ;
4497
4499
expect ( getVisibleChildren ( container ) ) . toEqual (
4498
4500
< div >
4499
4501
< p > A</ p >
@@ -4539,12 +4541,14 @@ describe('ReactDOMFizzServer', () => {
4539
4541
4540
4542
ReactDOMClient . hydrateRoot ( container , < App text = "replaced" /> , {
4541
4543
onRecoverableError ( error ) {
4542
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4544
+ Scheduler . log (
4545
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4546
+ ) ;
4543
4547
} ,
4544
4548
} ) ;
4545
4549
await waitForAll ( [
4546
- ' Logged recoverable error: Text content does not match server- rendered HTML.' ,
4547
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
4550
+ " Logged recoverable error: Hydration failed because the server rendered HTML didn't match the client." ,
4551
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4548
4552
] ) ;
4549
4553
4550
4554
expect ( getVisibleChildren ( container ) ) . toEqual (
@@ -4556,21 +4560,7 @@ describe('ReactDOMFizzServer', () => {
4556
4560
) ;
4557
4561
4558
4562
await waitForAll ( [ ] ) ;
4559
- if ( __DEV__ ) {
4560
- expect ( mockError . mock . calls . length ) . toBe ( 1 ) ;
4561
- expect ( mockError . mock . calls [ 0 ] ) . toEqual ( [
4562
- 'Warning: Text content did not match. Server: "%s" Client: "%s"%s' ,
4563
- 'initial' ,
4564
- 'replaced' ,
4565
- '\n' +
4566
- ' in h2 (at **)\n' +
4567
- ' in Suspense (at **)\n' +
4568
- ' in div (at **)\n' +
4569
- ' in App (at **)' ,
4570
- ] ) ;
4571
- } else {
4572
- expect ( mockError . mock . calls . length ) . toBe ( 0 ) ;
4573
- }
4563
+ expect ( mockError . mock . calls . length ) . toBe ( 0 ) ;
4574
4564
} finally {
4575
4565
console . error = originalConsoleError ;
4576
4566
}
@@ -4626,12 +4616,14 @@ describe('ReactDOMFizzServer', () => {
4626
4616
4627
4617
ReactDOMClient . hydrateRoot ( container , < App /> , {
4628
4618
onRecoverableError ( error ) {
4629
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4619
+ Scheduler . log (
4620
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4621
+ ) ;
4630
4622
} ,
4631
4623
} ) ;
4632
4624
await waitForAll ( [
4633
4625
'Logged recoverable error: uh oh' ,
4634
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
4626
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4635
4627
] ) ;
4636
4628
4637
4629
expect ( getVisibleChildren ( container ) ) . toEqual (
@@ -4713,7 +4705,9 @@ describe('ReactDOMFizzServer', () => {
4713
4705
4714
4706
ReactDOMClient . hydrateRoot ( container , < App /> , {
4715
4707
onRecoverableError ( error ) {
4716
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4708
+ Scheduler . log (
4709
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4710
+ ) ;
4717
4711
} ,
4718
4712
} ) ;
4719
4713
await waitForAll ( [
@@ -4722,7 +4716,7 @@ describe('ReactDOMFizzServer', () => {
4722
4716
// onRecoverableError because the UI recovered without surfacing the
4723
4717
// error to the user.
4724
4718
'Logged recoverable error: first error' ,
4725
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
4719
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4726
4720
] ) ;
4727
4721
expect ( mockError . mock . calls ) . toEqual ( [ ] ) ;
4728
4722
mockError . mockClear ( ) ;
@@ -4830,7 +4824,9 @@ describe('ReactDOMFizzServer', () => {
4830
4824
4831
4825
ReactDOMClient . hydrateRoot ( container , < App /> , {
4832
4826
onRecoverableError ( error ) {
4833
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4827
+ Scheduler . log (
4828
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4829
+ ) ;
4834
4830
} ,
4835
4831
} ) ;
4836
4832
await waitForAll ( [ 'suspending' ] ) ;
@@ -4847,7 +4843,7 @@ describe('ReactDOMFizzServer', () => {
4847
4843
await waitForAll ( [
4848
4844
'throwing: first error' ,
4849
4845
'Logged recoverable error: first error' ,
4850
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
4846
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4851
4847
] ) ;
4852
4848
expect ( getVisibleChildren ( container ) ) . toEqual (
4853
4849
< div >
@@ -4954,14 +4950,16 @@ describe('ReactDOMFizzServer', () => {
4954
4950
4955
4951
ReactDOMClient . hydrateRoot ( container , < App /> , {
4956
4952
onRecoverableError ( error ) {
4957
- Scheduler . log ( 'Logged recoverable error: ' + error . message ) ;
4953
+ Scheduler . log (
4954
+ 'Logged recoverable error: ' + normalizeError ( error . message ) ,
4955
+ ) ;
4958
4956
} ,
4959
4957
} ) ;
4960
4958
await waitForAll ( [
4961
4959
'throwing: first error' ,
4962
4960
'suspending' ,
4963
4961
'Logged recoverable error: first error' ,
4964
- 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering. ' ,
4962
+ 'Logged recoverable error: There was an error while hydrating this Suspense boundary.' ,
4965
4963
] ) ;
4966
4964
expect ( mockError . mock . calls ) . toEqual ( [ ] ) ;
4967
4965
mockError . mockClear ( ) ;
@@ -6341,13 +6339,7 @@ describe('ReactDOMFizzServer', () => {
6341
6339
} ) ;
6342
6340
await expect ( async ( ) => {
6343
6341
await waitForAll ( [ ] ) ;
6344
- } ) . toErrorDev (
6345
- [
6346
- 'Expected server HTML to contain a matching <span> in the root' ,
6347
- 'An error occurred during hydration' ,
6348
- ] ,
6349
- { withoutStack : 1 } ,
6350
- ) ;
6342
+ } ) . toErrorDev ( [ 'An error occurred during hydration' ] , { withoutStack : 1 } ) ;
6351
6343
expect ( errors . length ) . toEqual ( 2 ) ;
6352
6344
expect ( getVisibleChildren ( container ) ) . toEqual ( < span /> ) ;
6353
6345
} ) ;
0 commit comments