512
);
513
});
514
515
+ describe('Hooks', () => {
516
+ function DivWithId({children}) {
517
+ const id = React.useId();
518
+ return <div prop={id}>{children}</div>;
519
+ }
520
+
521
+ it('should support useId', () => {
522
+ function App() {
523
+ return (
524
+ <>
525
+ <DivWithId />
526
+ <DivWithId />
527
+ </>
528
+ );
529
+ }
530
+
531
+ const transport = ReactNoopFlightServer.render(<App />);
532
+ act(() => {
533
+ ReactNoop.render(ReactNoopFlightClient.read(transport));
534
+ });
535
+ expect(ReactNoop).toMatchRenderedOutput(
536
+ <>
537
+ <div prop=":S1:" />
538
+ <div prop=":S2:" />
539
+ </>,
540
+ );
541
+ });
542
+
543
+ it('accepts an identifier prefix that prefixes generated ids', () => {
544
+ function App() {
545
+ return (
546
+ <>
547
+ <DivWithId />
548
+ <DivWithId />
549
+ </>
550
+ );
551
+ }
552
+
553
+ const transport = ReactNoopFlightServer.render(<App />, {
554
+ identifierPrefix: 'foo',
555
+ });
556
+ act(() => {
557
+ ReactNoop.render(ReactNoopFlightClient.read(transport));
558
+ });
559
+ expect(ReactNoop).toMatchRenderedOutput(
560
+ <>
561
+ <div prop=":fooS1:" />
562
+ <div prop=":fooS2:" />
563
+ </>,
564
+ );
565
+ });
566
+
567
+ it('[TODO] it does not warn if you render a server element passed to a client module reference twice on the client when using useId', async () => {
568
+ // @TODO Today if you render a server component with useId and pass it to a client component and that client component renders the element in two or more
569
+ // places the id used on the server will be duplicated in the client. This is a deviation from the guarantees useId makes for Fizz/Client and is a consequence
570
+ // of the fact that the server component is actually rendered on the server and is reduced to a set of host elements before being passed to the Client component
571
+ // so the output passed to the Client has no knowledge of the useId use. In the future we would like to add a DEV warning when this happens. For now
572
+ // we just accept that it is a nuance of useId in Flight
573
+ function App() {
574
+ const id = React.useId();
575
+ const div = <div prop={id}>{id}</div>;
576
+ return <ClientDoublerModuleRef el={div} />;
577
+ }
578
+
579
+ function ClientDoubler({el}) {
580
+ Scheduler.unstable_yieldValue('ClientDoubler');
581
+ return (
582
+ <>
583
+ {el}
584
+ {el}
585
+ </>
586
+ );
587
+ }
588
+
589
+ const ClientDoublerModuleRef = moduleReference(ClientDoubler);
590
+
591
+ const transport = ReactNoopFlightServer.render(<App />);
592
+ expect(Scheduler).toHaveYielded([]);
593
+
594
+ act(() => {
595
+ ReactNoop.render(ReactNoopFlightClient.read(transport));
596
+ });
597
+
598
+ expect(Scheduler).toHaveYielded(['ClientDoubler']);
599
+ expect(ReactNoop).toMatchRenderedOutput(
600
+ <>
601
+ <div prop=":S1:">:S1:</div>
602
+ <div prop=":S1:">:S1:</div>
603
+ </>,
604
+ );
605
+ });
606
+ });
607
+
608
describe('ServerContext', () => {
609
// @gate enableServerContext
610
it('supports basic createServerContext usage', () => {
852
function Bar() {
853
return <span>{React.useContext(ServerContext)}</span>;
854
}
762
- const transport = ReactNoopFlightServer.render(<Bar />, {}, [
763
- ['ServerContext', 'Override'],
764
- ]);
855
+ const transport = ReactNoopFlightServer.render(<Bar />, {
856
+ context: [['ServerContext', 'Override']],
857
+ });
858
859
act(() => {
860
const flightModel = ReactNoopFlightClient.read(transport);
861
ReactNoop.render(flightModel);
862
});
770
-
863
expect(ReactNoop).toMatchRenderedOutput(<span>Override</span>);
864
});
865