7498
</div>,
7499
);
7500
});
7501
+
7502
+ // @gate enablePostpone
7503
+ it('does not call onError when you abort with a postpone instance during prerender', async () => {
7504
+ const promise = new Promise(r => {});
7505
+
7506
+ function Wait() {
7507
+ return React.use(promise);
7508
+ }
7509
+
7510
+ function App() {
7511
+ return (
7512
+ <div>
7513
+ <Suspense fallback="Loading...">
7514
+ <p>
7515
+ <span>
7516
+ <Suspense fallback="Loading again...">
7517
+ <Wait />
7518
+ </Suspense>
7519
+ </span>
7520
+ </p>
7521
+ <p>
7522
+ <span>
7523
+ <Suspense fallback="Loading again too...">
7524
+ <Wait />
7525
+ </Suspense>
7526
+ </span>
7527
+ </p>
7528
+ </Suspense>
7529
+ </div>
7530
+ );
7531
+ }
7532
+
7533
+ let postponeInstance;
7534
+ try {
7535
+ React.unstable_postpone('manufactured');
7536
+ } catch (p) {
7537
+ postponeInstance = p;
7538
+ }
7539
+
7540
+ const controller = new AbortController();
7541
+ const signal = controller.signal;
7542
+
7543
+ const errors = [];
7544
+ function onError(error) {
7545
+ errors.push(error);
7546
+ }
7547
+ const postpones = [];
7548
+ function onPostpone(reason) {
7549
+ postpones.push(reason);
7550
+ }
7551
+ let pendingPrerender;
7552
+ await act(() => {
7553
+ pendingPrerender = ReactDOMFizzStatic.prerenderToNodeStream(<App />, {
7554
+ signal,
7555
+ onError,
7556
+ onPostpone,
7557
+ });
7558
+ });
7559
+ controller.abort(postponeInstance);
7560
+
7561
+ const prerendered = await pendingPrerender;
7562
+
7563
+ expect(prerendered.postponed).toBe(null);
7564
+ expect(errors).toEqual([]);
7565
+ expect(postpones).toEqual(['manufactured', 'manufactured']);
7566
+
7567
+ await act(() => {
7568
+ prerendered.prelude.pipe(writable);
7569
+ });
7570
+
7571
+ expect(getVisibleChildren(container)).toEqual(
7572
+ <div>
7573
+ <p>
7574
+ <span>Loading again...</span>
7575
+ </p>
7576
+ <p>
7577
+ <span>Loading again too...</span>
7578
+ </p>
7579
+ </div>,
7580
+ );
7581
+ });
7582
+
7583
+ // @gate enablePostpone
7584
+ it('does not call onError when you abort with a postpone instance during resume', async () => {
7585
+ let prerendering = true;
7586
+ const promise = new Promise(r => {});
7587
+
7588
+ function Wait() {
7589
+ return React.use(promise);
7590
+ }
7591
+ function Postpone() {
7592
+ if (prerendering) {
7593
+ React.unstable_postpone();
7594
+ }
7595
+ return (
7596
+ <span>
7597
+ <Suspense fallback="Loading again...">
7598
+ <Wait />
7599
+ </Suspense>
7600
+ </span>
7601
+ );
7602
+ }
7603
+
7604
+ function App() {
7605
+ return (
7606
+ <div>
7607
+ <Suspense fallback="Loading...">
7608
+ <p>
7609
+ <Postpone />
7610
+ </p>
7611
+ <p>
7612
+ <Postpone />
7613
+ </p>
7614
+ </Suspense>
7615
+ </div>
7616
+ );
7617
+ }
7618
+
7619
+ const prerendered = await ReactDOMFizzStatic.prerenderToNodeStream(<App />);
7620
+ expect(prerendered.postponed).not.toBe(null);
7621
+
7622
+ prerendering = false;
7623
+
7624
+ // Create a separate stream so it doesn't close the writable. I.e. simple concat.
7625
+ const preludeWritable = new Stream.PassThrough();
7626
+ preludeWritable.setEncoding('utf8');
7627
+ preludeWritable.on('data', chunk => {
7628
+ writable.write(chunk);
7629
+ });
7630
+
7631
+ await act(() => {
7632
+ prerendered.prelude.pipe(preludeWritable);
7633
+ });
7634
+
7635
+ expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
7636
+
7637
+ let postponeInstance;
7638
+ try {
7639
+ React.unstable_postpone('manufactured');
7640
+ } catch (p) {
7641
+ postponeInstance = p;
7642
+ }
7643
+
7644
+ const errors = [];
7645
+ function onError(error) {
7646
+ errors.push(error);
7647
+ }
7648
+ const postpones = [];
7649
+ function onPostpone(reason) {
7650
+ postpones.push(reason);
7651
+ }
7652
+
7653
+ prerendering = false;
7654
+
7655
+ const resumed = await ReactDOMFizzServer.resumeToPipeableStream(
7656
+ <App />,
7657
+ JSON.parse(JSON.stringify(prerendered.postponed)),
7658
+ {
7659
+ onError,
7660
+ onPostpone,
7661
+ },
7662
+ );
7663
+
7664
+ await act(() => {
7665
+ resumed.pipe(writable);
7666
+ });
7667
+ await act(() => {
7668
+ resumed.abort(postponeInstance);
7669
+ });
7670
+
7671
+ expect(getVisibleChildren(container)).toEqual(
7672
+ <div>
7673
+ <p>
7674
+ <span>Loading again...</span>
7675
+ </p>
7676
+ <p>
7677
+ <span>Loading again...</span>
7678
+ </p>
7679
+ </div>,
7680
+ );
7681
+
7682
+ expect(errors).toEqual([]);
7683
+ expect(postpones).toEqual(['manufactured', 'manufactured']);
7684
+ });
7685
+
7686
+ // @gate enablePostpone
7687
+ it('does not call onError when you abort with a postpone instance during a render', async () => {
7688
+ const promise = new Promise(r => {});
7689
+
7690
+ function Wait() {
7691
+ return React.use(promise);
7692
+ }
7693
+
7694
+ function App() {
7695
+ return (
7696
+ <div>
7697
+ <Suspense fallback="Loading...">
7698
+ <p>
7699
+ <span>
7700
+ <Suspense fallback="Loading again...">
7701
+ <Wait />
7702
+ </Suspense>
7703
+ </span>
7704
+ </p>
7705
+ <p>
7706
+ <span>
7707
+ <Suspense fallback="Loading again...">
7708
+ <Wait />
7709
+ </Suspense>
7710
+ </span>
7711
+ </p>
7712
+ </Suspense>
7713
+ </div>
7714
+ );
7715
+ }
7716
+
7717
+ const errors = [];
7718
+ function onError(error) {
7719
+ errors.push(error);
7720
+ }
7721
+ const postpones = [];
7722
+ function onPostpone(reason) {
7723
+ postpones.push(reason);
7724
+ }
7725
+ const result = await renderToPipeableStream(<App />, {onError, onPostpone});
7726
+ await act(() => {
7727
+ result.pipe(writable);
7728
+ });
7729
+
7730
+ expect(getVisibleChildren(container)).toEqual(
7731
+ <div>
7732
+ <p>
7733
+ <span>Loading again...</span>
7734
+ </p>
7735
+ <p>
7736
+ <span>Loading again...</span>
7737
+ </p>
7738
+ </div>,
7739
+ );
7740
+
7741
+ let postponeInstance;
7742
+ try {
7743
+ React.unstable_postpone('manufactured');
7744
+ } catch (p) {
7745
+ postponeInstance = p;
7746
+ }
7747
+ await act(() => {
7748
+ result.abort(postponeInstance);
7749
+ });
7750
+
7751
+ expect(getVisibleChildren(container)).toEqual(
7752
+ <div>
7753
+ <p>
7754
+ <span>Loading again...</span>
7755
+ </p>
7756
+ <p>
7757
+ <span>Loading again...</span>
7758
+ </p>
7759
+ </div>,
7760
+ );
7761
+
7762
+ expect(errors).toEqual([]);
7763
+ expect(postpones).toEqual(['manufactured', 'manufactured']);
7764
+ });
7765
+
7766
+ // @gate enablePostpone
7767
+ it('fatally errors if you abort with a postpone in the shell during resume', async () => {
7768
+ let prerendering = true;
7769
+ const promise = new Promise(r => {});
7770
+
7771
+ function Wait() {
7772
+ return React.use(promise);
7773
+ }
7774
+ function Postpone() {
7775
+ if (prerendering) {
7776
+ React.unstable_postpone();
7777
+ }
7778
+ return (
7779
+ <span>
7780
+ <Suspense fallback="Loading again...">
7781
+ <Wait />
7782
+ </Suspense>
7783
+ </span>
7784
+ );
7785
+ }
7786
+
7787
+ function PostponeInShell() {
7788
+ if (prerendering) {
7789
+ React.unstable_postpone();
7790
+ }
7791
+ return <span>in shell</span>;
7792
+ }
7793
+
7794
+ function App() {
7795
+ return (
7796
+ <div>
7797
+ <PostponeInShell />
7798
+ <Suspense fallback="Loading...">
7799
+ <p>
7800
+ <Postpone />
7801
+ </p>
7802
+ <p>
7803
+ <Postpone />
7804
+ </p>
7805
+ </Suspense>
7806
+ </div>
7807
+ );
7808
+ }
7809
+
7810
+ const prerendered = await ReactDOMFizzStatic.prerenderToNodeStream(<App />);
7811
+ expect(prerendered.postponed).not.toBe(null);
7812
+
7813
+ prerendering = false;
7814
+
7815
+ // Create a separate stream so it doesn't close the writable. I.e. simple concat.
7816
+ const preludeWritable = new Stream.PassThrough();
7817
+ preludeWritable.setEncoding('utf8');
7818
+ preludeWritable.on('data', chunk => {
7819
+ writable.write(chunk);
7820
+ });
7821
+
7822
+ await act(() => {
7823
+ prerendered.prelude.pipe(preludeWritable);
7824
+ });
7825
+
7826
+ expect(getVisibleChildren(container)).toEqual(undefined);
7827
+
7828
+ let postponeInstance;
7829
+ try {
7830
+ React.unstable_postpone('manufactured');
7831
+ } catch (p) {
7832
+ postponeInstance = p;
7833
+ }
7834
+
7835
+ const errors = [];
7836
+ function onError(error) {
7837
+ errors.push(error);
7838
+ }
7839
+ const shellErrors = [];
7840
+ function onShellError(error) {
7841
+ shellErrors.push(error);
7842
+ }
7843
+ const postpones = [];
7844
+ function onPostpone(reason) {
7845
+ postpones.push(reason);
7846
+ }
7847
+
7848
+ prerendering = false;
7849
+
7850
+ const resumed = await ReactDOMFizzServer.resumeToPipeableStream(
7851
+ <App />,
7852
+ JSON.parse(JSON.stringify(prerendered.postponed)),
7853
+ {
7854
+ onError,
7855
+ onShellError,
7856
+ onPostpone,
7857
+ },
7858
+ );
7859
+ await act(() => {
7860
+ resumed.abort(postponeInstance);
7861
+ });
7862
+ expect(errors).toEqual([
7863
+ new Error(
7864
+ 'The render was aborted with postpone when the shell is incomplete. Reason: manufactured',
7865
+ ),
7866
+ ]);
7867
+ expect(shellErrors).toEqual([
7868
+ new Error(
7869
+ 'The render was aborted with postpone when the shell is incomplete. Reason: manufactured',
7870
+ ),
7871
+ ]);
7872
+ expect(postpones).toEqual([]);
7873
+ });
7874
+
7875
+ // @gate enablePostpone
7876
+ it('fatally errors if you abort with a postpone in the shell during render', async () => {
7877
+ const promise = new Promise(r => {});
7878
+
7879
+ function Wait() {
7880
+ return React.use(promise);
7881
+ }
7882
+
7883
+ function App() {
7884
+ return (
7885
+ <div>
7886
+ <Suspense fallback="Loading...">
7887
+ <p>
7888
+ <span>
7889
+ <Suspense fallback="Loading again...">
7890
+ <Wait />
7891
+ </Suspense>
7892
+ </span>
7893
+ </p>
7894
+ <p>
7895
+ <span>
7896
+ <Suspense fallback="Loading again...">
7897
+ <Wait />
7898
+ </Suspense>
7899
+ </span>
7900
+ </p>
7901
+ </Suspense>
7902
+ </div>
7903
+ );
7904
+ }
7905
+
7906
+ const errors = [];
7907
+ function onError(error) {
7908
+ errors.push(error);
7909
+ }
7910
+ const shellErrors = [];
7911
+ function onShellError(error) {
7912
+ shellErrors.push(error);
7913
+ }
7914
+ const postpones = [];
7915
+ function onPostpone(reason) {
7916
+ postpones.push(reason);
7917
+ }
7918
+ const result = await renderToPipeableStream(<App />, {
7919
+ onError,
7920
+ onShellError,
7921
+ onPostpone,
7922
+ });
7923
+
7924
+ let postponeInstance;
7925
+ try {
7926
+ React.unstable_postpone('manufactured');
7927
+ } catch (p) {
7928
+ postponeInstance = p;
7929
+ }
7930
+ await act(() => {
7931
+ result.abort(postponeInstance);
7932
+ });
7933
+
7934
+ expect(getVisibleChildren(container)).toEqual(undefined);
7935
+
7936
+ expect(errors).toEqual([
7937
+ new Error(
7938
+ 'The render was aborted with postpone when the shell is incomplete. Reason: manufactured',
7939
+ ),
7940
+ ]);
7941
+ expect(shellErrors).toEqual([
7942
+ new Error(
7943
+ 'The render was aborted with postpone when the shell is incomplete. Reason: manufactured',
7944
+ ),
7945
+ ]);
7946
+ expect(postpones).toEqual([]);
7947
+ });
7948
});