1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @emails react-core
    
  8.  * @jest-environment node
    
  9.  */
    
  10. 
    
  11. 'use strict';
    
  12. 
    
  13. let Stream;
    
  14. let React;
    
  15. let ReactDOMFizzServer;
    
  16. let Suspense;
    
  17. 
    
  18. describe('ReactDOMFizzServerNode', () => {
    
  19.   beforeEach(() => {
    
  20.     jest.resetModules();
    
  21.     React = require('react');
    
  22.     ReactDOMFizzServer = require('react-dom/server');
    
  23.     Stream = require('stream');
    
  24.     Suspense = React.Suspense;
    
  25.   });
    
  26. 
    
  27.   function getTestWritable() {
    
  28.     const writable = new Stream.PassThrough();
    
  29.     writable.setEncoding('utf8');
    
  30.     const output = {result: '', error: undefined};
    
  31.     writable.on('data', chunk => {
    
  32.       output.result += chunk;
    
  33.     });
    
  34.     writable.on('error', error => {
    
  35.       output.error = error;
    
  36.     });
    
  37.     const completed = new Promise(resolve => {
    
  38.       writable.on('finish', () => {
    
  39.         resolve();
    
  40.       });
    
  41.       writable.on('error', () => {
    
  42.         resolve();
    
  43.       });
    
  44.     });
    
  45.     return {writable, completed, output};
    
  46.   }
    
  47. 
    
  48.   const theError = new Error('This is an error');
    
  49.   function Throw() {
    
  50.     throw theError;
    
  51.   }
    
  52.   const theInfinitePromise = new Promise(() => {});
    
  53.   function InfiniteSuspend() {
    
  54.     throw theInfinitePromise;
    
  55.   }
    
  56. 
    
  57.   it('should call renderToPipeableStream', () => {
    
  58.     const {writable, output} = getTestWritable();
    
  59.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  60.       <div>hello world</div>,
    
  61.     );
    
  62.     pipe(writable);
    
  63.     jest.runAllTimers();
    
  64.     expect(output.result).toMatchInlineSnapshot(`"<div>hello world</div>"`);
    
  65.   });
    
  66. 
    
  67.   it('should emit DOCTYPE at the root of the document', () => {
    
  68.     const {writable, output} = getTestWritable();
    
  69.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  70.       <html>
    
  71.         <body>hello world</body>
    
  72.       </html>,
    
  73.     );
    
  74.     pipe(writable);
    
  75.     jest.runAllTimers();
    
  76.     if (gate(flags => flags.enableFloat)) {
    
  77.       // with Float, we emit empty heads if they are elided when rendering <html>
    
  78.       expect(output.result).toMatchInlineSnapshot(
    
  79.         `"<!DOCTYPE html><html><head></head><body>hello world</body></html>"`,
    
  80.       );
    
  81.     } else {
    
  82.       expect(output.result).toMatchInlineSnapshot(
    
  83.         `"<!DOCTYPE html><html><body>hello world</body></html>"`,
    
  84.       );
    
  85.     }
    
  86.   });
    
  87. 
    
  88.   it('should emit bootstrap script src at the end', () => {
    
  89.     const {writable, output} = getTestWritable();
    
  90.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  91.       <div>hello world</div>,
    
  92.       {
    
  93.         bootstrapScriptContent: 'INIT();',
    
  94.         bootstrapScripts: ['init.js'],
    
  95.         bootstrapModules: ['init.mjs'],
    
  96.       },
    
  97.     );
    
  98.     pipe(writable);
    
  99.     jest.runAllTimers();
    
  100.     expect(output.result).toMatchInlineSnapshot(
    
  101.       `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script>INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
    
  102.     );
    
  103.   });
    
  104. 
    
  105.   it('should start writing after pipe', () => {
    
  106.     const {writable, output} = getTestWritable();
    
  107.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  108.       <div>hello world</div>,
    
  109.     );
    
  110.     jest.runAllTimers();
    
  111.     // First we write our header.
    
  112.     output.result +=
    
  113.       '<!doctype html><html><head><title>test</title><head><body>';
    
  114.     // Then React starts writing.
    
  115.     pipe(writable);
    
  116.     expect(output.result).toMatchInlineSnapshot(
    
  117.       `"<!doctype html><html><head><title>test</title><head><body><div>hello world</div>"`,
    
  118.     );
    
  119.   });
    
  120. 
    
  121.   it('emits all HTML as one unit if we wait until the end to start', async () => {
    
  122.     let hasLoaded = false;
    
  123.     let resolve;
    
  124.     const promise = new Promise(r => (resolve = r));
    
  125.     function Wait() {
    
  126.       if (!hasLoaded) {
    
  127.         throw promise;
    
  128.       }
    
  129.       return 'Done';
    
  130.     }
    
  131.     let isCompleteCalls = 0;
    
  132.     const {writable, output} = getTestWritable();
    
  133.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  134.       <div>
    
  135.         <Suspense fallback="Loading">
    
  136.           <Wait />
    
  137.         </Suspense>
    
  138.       </div>,
    
  139. 
    
  140.       {
    
  141.         onAllReady() {
    
  142.           isCompleteCalls++;
    
  143.         },
    
  144.       },
    
  145.     );
    
  146.     await jest.runAllTimers();
    
  147.     expect(output.result).toBe('');
    
  148.     expect(isCompleteCalls).toBe(0);
    
  149.     // Resolve the loading.
    
  150.     hasLoaded = true;
    
  151.     await resolve();
    
  152. 
    
  153.     await jest.runAllTimers();
    
  154. 
    
  155.     expect(output.result).toBe('');
    
  156.     expect(isCompleteCalls).toBe(1);
    
  157. 
    
  158.     // First we write our header.
    
  159.     output.result +=
    
  160.       '<!doctype html><html><head><title>test</title><head><body>';
    
  161.     // Then React starts writing.
    
  162.     pipe(writable);
    
  163.     expect(output.result).toMatchInlineSnapshot(
    
  164.       `"<!doctype html><html><head><title>test</title><head><body><div><!--$-->Done<!-- --><!--/$--></div>"`,
    
  165.     );
    
  166.   });
    
  167. 
    
  168.   it('should error the stream when an error is thrown at the root', async () => {
    
  169.     const reportedErrors = [];
    
  170.     const reportedShellErrors = [];
    
  171.     const {writable, output, completed} = getTestWritable();
    
  172.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  173.       <div>
    
  174.         <Throw />
    
  175.       </div>,
    
  176.       {
    
  177.         onError(x) {
    
  178.           reportedErrors.push(x);
    
  179.         },
    
  180.         onShellError(x) {
    
  181.           reportedShellErrors.push(x);
    
  182.         },
    
  183.       },
    
  184.     );
    
  185. 
    
  186.     // The stream is errored once we start writing.
    
  187.     pipe(writable);
    
  188. 
    
  189.     await completed;
    
  190. 
    
  191.     expect(output.error).toBe(theError);
    
  192.     expect(output.result).toBe('');
    
  193.     // This type of error is reported to the error callback too.
    
  194.     expect(reportedErrors).toEqual([theError]);
    
  195.     expect(reportedShellErrors).toEqual([theError]);
    
  196.   });
    
  197. 
    
  198.   it('should error the stream when an error is thrown inside a fallback', async () => {
    
  199.     const reportedErrors = [];
    
  200.     const reportedShellErrors = [];
    
  201.     const {writable, output, completed} = getTestWritable();
    
  202.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  203.       <div>
    
  204.         <Suspense fallback={<Throw />}>
    
  205.           <InfiniteSuspend />
    
  206.         </Suspense>
    
  207.       </div>,
    
  208. 
    
  209.       {
    
  210.         onError(x) {
    
  211.           reportedErrors.push(x.message);
    
  212.         },
    
  213.         onShellError(x) {
    
  214.           reportedShellErrors.push(x);
    
  215.         },
    
  216.       },
    
  217.     );
    
  218.     pipe(writable);
    
  219. 
    
  220.     await completed;
    
  221. 
    
  222.     expect(output.error).toBe(theError);
    
  223.     expect(output.result).toBe('');
    
  224.     expect(reportedErrors).toEqual([
    
  225.       theError.message,
    
  226.       'The destination stream errored while writing data.',
    
  227.     ]);
    
  228.     expect(reportedShellErrors).toEqual([theError]);
    
  229.   });
    
  230. 
    
  231.   it('should not error the stream when an error is thrown inside suspense boundary', async () => {
    
  232.     const reportedErrors = [];
    
  233.     const reportedShellErrors = [];
    
  234.     const {writable, output, completed} = getTestWritable();
    
  235.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  236.       <div>
    
  237.         <Suspense fallback={<div>Loading</div>}>
    
  238.           <Throw />
    
  239.         </Suspense>
    
  240.       </div>,
    
  241.       {
    
  242.         onError(x) {
    
  243.           reportedErrors.push(x);
    
  244.         },
    
  245.         onShellError(x) {
    
  246.           reportedShellErrors.push(x);
    
  247.         },
    
  248.       },
    
  249.     );
    
  250.     pipe(writable);
    
  251. 
    
  252.     await completed;
    
  253. 
    
  254.     expect(output.error).toBe(undefined);
    
  255.     expect(output.result).toContain('Loading');
    
  256.     // While no error is reported to the stream, the error is reported to the callback.
    
  257.     expect(reportedErrors).toEqual([theError]);
    
  258.     expect(reportedShellErrors).toEqual([]);
    
  259.   });
    
  260. 
    
  261.   it('should not attempt to render the fallback if the main content completes first', async () => {
    
  262.     const {writable, output, completed} = getTestWritable();
    
  263. 
    
  264.     let renderedFallback = false;
    
  265.     function Fallback() {
    
  266.       renderedFallback = true;
    
  267.       return 'Loading...';
    
  268.     }
    
  269.     function Content() {
    
  270.       return 'Hi';
    
  271.     }
    
  272.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  273.       <Suspense fallback={<Fallback />}>
    
  274.         <Content />
    
  275.       </Suspense>,
    
  276.     );
    
  277.     pipe(writable);
    
  278. 
    
  279.     await completed;
    
  280. 
    
  281.     expect(output.result).toContain('Hi');
    
  282.     expect(output.result).not.toContain('Loading');
    
  283.     expect(renderedFallback).toBe(false);
    
  284.   });
    
  285. 
    
  286.   it('should be able to complete by aborting even if the promise never resolves', async () => {
    
  287.     let isCompleteCalls = 0;
    
  288.     const errors = [];
    
  289.     const {writable, output, completed} = getTestWritable();
    
  290.     const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
    
  291.       <div>
    
  292.         <Suspense fallback={<div>Loading</div>}>
    
  293.           <InfiniteSuspend />
    
  294.         </Suspense>
    
  295.       </div>,
    
  296.       {
    
  297.         onError(x) {
    
  298.           errors.push(x.message);
    
  299.         },
    
  300.         onAllReady() {
    
  301.           isCompleteCalls++;
    
  302.         },
    
  303.       },
    
  304.     );
    
  305.     pipe(writable);
    
  306. 
    
  307.     jest.runAllTimers();
    
  308. 
    
  309.     expect(output.result).toContain('Loading');
    
  310.     expect(isCompleteCalls).toBe(0);
    
  311. 
    
  312.     abort(new Error('uh oh'));
    
  313. 
    
  314.     await completed;
    
  315. 
    
  316.     expect(errors).toEqual(['uh oh']);
    
  317.     expect(output.error).toBe(undefined);
    
  318.     expect(output.result).toContain('Loading');
    
  319.     expect(isCompleteCalls).toBe(1);
    
  320.   });
    
  321. 
    
  322.   it('should fail the shell if you abort before work has begun', async () => {
    
  323.     let isCompleteCalls = 0;
    
  324.     const errors = [];
    
  325.     const shellErrors = [];
    
  326.     const {writable, output, completed} = getTestWritable();
    
  327.     const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
    
  328.       <div>
    
  329.         <Suspense fallback={<div>Loading</div>}>
    
  330.           <InfiniteSuspend />
    
  331.         </Suspense>
    
  332.       </div>,
    
  333.       {
    
  334.         onError(x) {
    
  335.           errors.push(x.message);
    
  336.         },
    
  337.         onShellError(x) {
    
  338.           shellErrors.push(x.message);
    
  339.         },
    
  340.         onAllReady() {
    
  341.           isCompleteCalls++;
    
  342.         },
    
  343.       },
    
  344.     );
    
  345.     pipe(writable);
    
  346. 
    
  347.     // Currently we delay work so if we abort, we abort the remaining CPU
    
  348.     // work as well.
    
  349. 
    
  350.     // Abort before running the timers that perform the work
    
  351.     const theReason = new Error('uh oh');
    
  352.     abort(theReason);
    
  353. 
    
  354.     jest.runAllTimers();
    
  355. 
    
  356.     await completed;
    
  357. 
    
  358.     expect(errors).toEqual(['uh oh']);
    
  359.     expect(shellErrors).toEqual(['uh oh']);
    
  360.     expect(output.error).toBe(theReason);
    
  361.     expect(output.result).toBe('');
    
  362.     expect(isCompleteCalls).toBe(0);
    
  363.   });
    
  364. 
    
  365.   it('should be able to complete by abort when the fallback is also suspended', async () => {
    
  366.     let isCompleteCalls = 0;
    
  367.     const errors = [];
    
  368.     const {writable, output, completed} = getTestWritable();
    
  369.     const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
    
  370.       <div>
    
  371.         <Suspense fallback="Loading">
    
  372.           <Suspense fallback={<InfiniteSuspend />}>
    
  373.             <InfiniteSuspend />
    
  374.           </Suspense>
    
  375.         </Suspense>
    
  376.       </div>,
    
  377.       {
    
  378.         onError(x) {
    
  379.           errors.push(x.message);
    
  380.         },
    
  381.         onAllReady() {
    
  382.           isCompleteCalls++;
    
  383.         },
    
  384.       },
    
  385.     );
    
  386.     pipe(writable);
    
  387. 
    
  388.     jest.runAllTimers();
    
  389. 
    
  390.     expect(output.result).toContain('Loading');
    
  391.     expect(isCompleteCalls).toBe(0);
    
  392. 
    
  393.     abort();
    
  394. 
    
  395.     await completed;
    
  396. 
    
  397.     expect(errors).toEqual([
    
  398.       // There are two boundaries that abort
    
  399.       'The render was aborted by the server without a reason.',
    
  400.       'The render was aborted by the server without a reason.',
    
  401.     ]);
    
  402.     expect(output.error).toBe(undefined);
    
  403.     expect(output.result).toContain('Loading');
    
  404.     expect(isCompleteCalls).toBe(1);
    
  405.   });
    
  406. 
    
  407.   it('should be able to get context value when promise resolves', async () => {
    
  408.     class DelayClient {
    
  409.       get() {
    
  410.         if (this.resolved) return this.resolved;
    
  411.         if (this.pending) return this.pending;
    
  412.         return (this.pending = new Promise(resolve => {
    
  413.           setTimeout(() => {
    
  414.             delete this.pending;
    
  415.             this.resolved = 'OK';
    
  416.             resolve();
    
  417.           }, 500);
    
  418.         }));
    
  419.       }
    
  420.     }
    
  421. 
    
  422.     const DelayContext = React.createContext(undefined);
    
  423.     const Component = () => {
    
  424.       const client = React.useContext(DelayContext);
    
  425.       if (!client) {
    
  426.         return 'context not found.';
    
  427.       }
    
  428.       const result = client.get();
    
  429.       if (typeof result === 'string') {
    
  430.         return result;
    
  431.       }
    
  432.       throw result;
    
  433.     };
    
  434. 
    
  435.     const client = new DelayClient();
    
  436.     const {writable, output, completed} = getTestWritable();
    
  437.     ReactDOMFizzServer.renderToPipeableStream(
    
  438.       <DelayContext.Provider value={client}>
    
  439.         <Suspense fallback="loading">
    
  440.           <Component />
    
  441.         </Suspense>
    
  442.       </DelayContext.Provider>,
    
  443.     ).pipe(writable);
    
  444. 
    
  445.     jest.runAllTimers();
    
  446. 
    
  447.     expect(output.error).toBe(undefined);
    
  448.     expect(output.result).toContain('loading');
    
  449. 
    
  450.     await completed;
    
  451. 
    
  452.     expect(output.error).toBe(undefined);
    
  453.     expect(output.result).not.toContain('context never found');
    
  454.     expect(output.result).toContain('OK');
    
  455.   });
    
  456. 
    
  457.   it('should be able to get context value when calls renderToPipeableStream twice at the same time', async () => {
    
  458.     class DelayClient {
    
  459.       get() {
    
  460.         if (this.resolved) return this.resolved;
    
  461.         if (this.pending) return this.pending;
    
  462.         return (this.pending = new Promise(resolve => {
    
  463.           setTimeout(() => {
    
  464.             delete this.pending;
    
  465.             this.resolved = 'OK';
    
  466.             resolve();
    
  467.           }, 500);
    
  468.         }));
    
  469.       }
    
  470.     }
    
  471.     const DelayContext = React.createContext(undefined);
    
  472.     const Component = () => {
    
  473.       const client = React.useContext(DelayContext);
    
  474.       if (!client) {
    
  475.         return 'context never found';
    
  476.       }
    
  477.       const result = client.get();
    
  478.       if (typeof result === 'string') {
    
  479.         return result;
    
  480.       }
    
  481.       throw result;
    
  482.     };
    
  483. 
    
  484.     const client0 = new DelayClient();
    
  485.     const {
    
  486.       writable: writable0,
    
  487.       output: output0,
    
  488.       completed: completed0,
    
  489.     } = getTestWritable();
    
  490.     ReactDOMFizzServer.renderToPipeableStream(
    
  491.       <DelayContext.Provider value={client0}>
    
  492.         <Suspense fallback="loading">
    
  493.           <Component />
    
  494.         </Suspense>
    
  495.       </DelayContext.Provider>,
    
  496.     ).pipe(writable0);
    
  497. 
    
  498.     const client1 = new DelayClient();
    
  499.     const {
    
  500.       writable: writable1,
    
  501.       output: output1,
    
  502.       completed: completed1,
    
  503.     } = getTestWritable();
    
  504.     ReactDOMFizzServer.renderToPipeableStream(
    
  505.       <DelayContext.Provider value={client1}>
    
  506.         <Suspense fallback="loading">
    
  507.           <Component />
    
  508.         </Suspense>
    
  509.       </DelayContext.Provider>,
    
  510.     ).pipe(writable1);
    
  511. 
    
  512.     jest.runAllTimers();
    
  513. 
    
  514.     expect(output0.error).toBe(undefined);
    
  515.     expect(output0.result).toContain('loading');
    
  516. 
    
  517.     expect(output1.error).toBe(undefined);
    
  518.     expect(output1.result).toContain('loading');
    
  519. 
    
  520.     await Promise.all([completed0, completed1]);
    
  521. 
    
  522.     expect(output0.error).toBe(undefined);
    
  523.     expect(output0.result).not.toContain('context never found');
    
  524.     expect(output0.result).toContain('OK');
    
  525. 
    
  526.     expect(output1.error).toBe(undefined);
    
  527.     expect(output1.result).not.toContain('context never found');
    
  528.     expect(output1.result).toContain('OK');
    
  529.   });
    
  530. 
    
  531.   it('should be able to pop context after suspending', async () => {
    
  532.     class DelayClient {
    
  533.       get() {
    
  534.         if (this.resolved) return this.resolved;
    
  535.         if (this.pending) return this.pending;
    
  536.         return (this.pending = new Promise(resolve => {
    
  537.           setTimeout(() => {
    
  538.             delete this.pending;
    
  539.             this.resolved = 'OK';
    
  540.             resolve();
    
  541.           }, 500);
    
  542.         }));
    
  543.       }
    
  544.     }
    
  545. 
    
  546.     const DelayContext = React.createContext(undefined);
    
  547.     const Component = () => {
    
  548.       const client = React.useContext(DelayContext);
    
  549.       if (!client) {
    
  550.         return 'context not found.';
    
  551.       }
    
  552.       const result = client.get();
    
  553.       if (typeof result === 'string') {
    
  554.         return result;
    
  555.       }
    
  556.       throw result;
    
  557.     };
    
  558. 
    
  559.     const client = new DelayClient();
    
  560.     const {writable, output, completed} = getTestWritable();
    
  561.     ReactDOMFizzServer.renderToPipeableStream(
    
  562.       <>
    
  563.         <DelayContext.Provider value={client}>
    
  564.           <Suspense fallback="loading">
    
  565.             <Component />
    
  566.           </Suspense>
    
  567.         </DelayContext.Provider>
    
  568.         <DelayContext.Provider value={client}>
    
  569.           <Suspense fallback="loading">
    
  570.             <Component />
    
  571.           </Suspense>
    
  572.         </DelayContext.Provider>
    
  573.       </>,
    
  574.     ).pipe(writable);
    
  575. 
    
  576.     jest.runAllTimers();
    
  577. 
    
  578.     expect(output.error).toBe(undefined);
    
  579.     expect(output.result).toContain('loading');
    
  580. 
    
  581.     await completed;
    
  582. 
    
  583.     expect(output.error).toBe(undefined);
    
  584.     expect(output.result).not.toContain('context never found');
    
  585.     expect(output.result).toContain('OK');
    
  586.   });
    
  587. 
    
  588.   it('should not continue rendering after the writable ends unexpectedly', async () => {
    
  589.     let hasLoaded = false;
    
  590.     let resolve;
    
  591.     let isComplete = false;
    
  592.     let rendered = false;
    
  593.     const promise = new Promise(r => (resolve = r));
    
  594.     function Wait() {
    
  595.       if (!hasLoaded) {
    
  596.         throw promise;
    
  597.       }
    
  598.       rendered = true;
    
  599.       return 'Done';
    
  600.     }
    
  601.     const errors = [];
    
  602.     const {writable, completed} = getTestWritable();
    
  603.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  604.       <div>
    
  605.         <Suspense fallback={<div>Loading</div>}>
    
  606.           <Wait />
    
  607.         </Suspense>
    
  608.       </div>,
    
  609.       {
    
  610.         onError(x) {
    
  611.           errors.push(x.message);
    
  612.         },
    
  613.         onAllReady() {
    
  614.           isComplete = true;
    
  615.         },
    
  616.       },
    
  617.     );
    
  618.     pipe(writable);
    
  619. 
    
  620.     expect(rendered).toBe(false);
    
  621.     expect(isComplete).toBe(false);
    
  622. 
    
  623.     writable.end();
    
  624. 
    
  625.     await jest.runAllTimers();
    
  626. 
    
  627.     hasLoaded = true;
    
  628.     resolve();
    
  629. 
    
  630.     await completed;
    
  631. 
    
  632.     expect(errors).toEqual([
    
  633.       'The destination stream errored while writing data.',
    
  634.     ]);
    
  635.     expect(rendered).toBe(false);
    
  636.     expect(isComplete).toBe(true);
    
  637.   });
    
  638. 
    
  639.   it('should encode multibyte characters correctly without nulls (#24985)', () => {
    
  640.     const {writable, output} = getTestWritable();
    
  641.     const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
    
  642.       <div>{Array(700).fill('ののの')}</div>,
    
  643.     );
    
  644.     pipe(writable);
    
  645.     jest.runAllTimers();
    
  646.     expect(output.result.indexOf('\u0000')).toBe(-1);
    
  647.     expect(output.result).toEqual(
    
  648.       '<div>' + Array(700).fill('ののの').join('<!-- -->') + '</div>',
    
  649.     );
    
  650.   });
    
  651. });