Failing test for Client reconciliation (#20318)
Dan Abramov committed
Dec 1, 2020 at 16:40 UTC
148ffe3cfe7a2627bebfb1852f332a1d122b3103
1 file changed
+88
packages/react-transport-dom-webpack/src/__tests__/ReactFlightDOM-test.js
+88
@@ -440,4 +440,92 @@ describe('ReactFlightDOM', () => {
440
'<p>Game over</p>', // TODO: should not have message in prod.
441
);
442
});
443
+
444
+ // @gate experimental
445
+ it('should preserve state of client components on refetch', async () => {
446
+ const {Suspense} = React;
447
+
448
+ // Client
449
+
450
+ function Page({response}) {
451
+ return response.readRoot();
452
+ }
453
+
454
+ function Input() {
455
+ return <input />;
456
+ }
457
+
458
+ const InputClient = moduleReference(Input);
459
+
460
+ // Server
461
+
462
+ function App({color}) {
463
+ // Verify both DOM and Client children.
464
+ return (
465
+ <div style={{color}}>
466
+ <input />
467
+ <InputClient />
468
+ </div>
469
+ );
470
+ }
471
+
472
+ const container = document.createElement('div');
473
+ const root = ReactDOM.unstable_createRoot(container);
474
+
475
+ const stream1 = getTestStream();
476
+ ReactTransportDOMServer.pipeToNodeWritable(
477
+ <App color="red" />,
478
+ stream1.writable,
479
+ webpackMap,
480
+ );
481
+ const response1 = ReactTransportDOMClient.createFromReadableStream(
482
+ stream1.readable,
483
+ );
484
+ await act(async () => {
485
+ root.render(
486
+ <Suspense fallback={<p>(loading)</p>}>
487
+ <Page response={response1} />
488
+ </Suspense>,
489
+ );
490
+ });
491
+ expect(container.children.length).toBe(1);
492
+ expect(container.children[0].tagName).toBe('DIV');
493
+ expect(container.children[0].style.color).toBe('red');
494
+
495
+ // Change the DOM state for both inputs.
496
+ const inputA = container.children[0].children[0];
497
+ expect(inputA.tagName).toBe('INPUT');
498
+ inputA.value = 'hello';
499
+ const inputB = container.children[0].children[1];
500
+ expect(inputB.tagName).toBe('INPUT');
501
+ inputB.value = 'goodbye';
502
+
503
+ const stream2 = getTestStream();
504
+ ReactTransportDOMServer.pipeToNodeWritable(
505
+ <App color="blue" />,
506
+ stream2.writable,
507
+ webpackMap,
508
+ );
509
+ const response2 = ReactTransportDOMClient.createFromReadableStream(
510
+ stream2.readable,
511
+ );
512
+ await act(async () => {
513
+ root.render(
514
+ <Suspense fallback={<p>(loading)</p>}>
515
+ <Page response={response2} />
516
+ </Suspense>,
517
+ );
518
+ });
519
+ expect(container.children.length).toBe(1);
520
+ expect(container.children[0].tagName).toBe('DIV');
521
+ expect(container.children[0].style.color).toBe('blue');
522
+
523
+ // Verify we didn't destroy the DOM for either input.
524
+ expect(inputA === container.children[0].children[0]).toBe(true);
525
+ expect(inputA.tagName).toBe('INPUT');
526
+ expect(inputA.value).toBe('hello');
527
+ expect(inputB === container.children[0].children[1]).toBe(true);
528
+ expect(inputB.tagName).toBe('INPUT');
529
+ expect(inputB.value).toBe('goodbye');
530
+ });
531
});